diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index ca5e494f..7d04bb2f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -30,7 +30,7 @@ jobs: run: yarn workspace @ampleforthorg/spot-contracts run coverage - name: spot-contracts report coverage - uses: coverallsapp/github-action@v2.3.0 + uses: coverallsapp/github-action@v2.3.6 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: "./spot-contracts/coverage/lcov.info" @@ -39,7 +39,7 @@ jobs: run: yarn workspace @ampleforthorg/spot-vaults run coverage - name: spot-vaults report coverage - uses: coverallsapp/github-action@v2.3.0 + uses: coverallsapp/github-action@v2.3.6 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: "./spot-vaults/coverage/lcov.info" diff --git a/.gitignore b/.gitignore index 8261c8d3..48cb62f1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ node_modules coverage coverage.json typechain +typechain-types #Hardhat files cache @@ -21,4 +22,4 @@ artifacts #Generated files RolloverBatch.json -RedeemBatch.json \ No newline at end of file +RedeemBatch.json diff --git a/README.md b/README.md index 9e759317..56eacafb 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Security contact: [dev-support@ampleforth.org](mailto:dev-support@ampleforth.org ### Package organization * [spot-contracts](./spot-contracts): SPOT protocol smart contracts. +* [spot-vaults](./spot-vaults): Vault strategies leveraging the SPOT system. * [spot-subgraph](./spot-subgraph): Subgraph to index SPOT protocol on-chain data. ## Licensing diff --git a/spot-contracts/.openzeppelin/mainnet.json b/spot-contracts/.openzeppelin/mainnet.json index e139eb59..04b7f534 100644 --- a/spot-contracts/.openzeppelin/mainnet.json +++ b/spot-contracts/.openzeppelin/mainnet.json @@ -2605,7 +2605,7 @@ "label": "feePolicy", "offset": 0, "slot": "302", - "type": "t_contract(IFeePolicy)11570", + "type": "t_contract(IFeePolicy)11619", "contract": "PerpetualTranche", "src": "contracts/PerpetualTranche.sol:132" }, @@ -2629,7 +2629,7 @@ "label": "bondIssuer", "offset": 0, "slot": "305", - "type": "t_contract(IBondIssuer)11490", + "type": "t_contract(IBondIssuer)11539", "contract": "PerpetualTranche", "src": "contracts/PerpetualTranche.sol:150" }, @@ -2637,7 +2637,7 @@ "label": "_depositBond", "offset": 0, "slot": "306", - "type": "t_contract(IBondController)12129", + "type": "t_contract(IBondController)12178", "contract": "PerpetualTranche", "src": "contracts/PerpetualTranche.sol:153" }, @@ -2685,7 +2685,7 @@ "label": "_mintedSupplyPerTranche_DEPRECATED", "offset": 0, "slot": "312", - "type": "t_mapping(t_contract(ITranche)12156,t_uint256)", + "type": "t_mapping(t_contract(ITranche)12205,t_uint256)", "contract": "PerpetualTranche", "src": "contracts/PerpetualTranche.sol:182" }, @@ -2717,7 +2717,7 @@ "label": "vault", "offset": 0, "slot": "317", - "type": "t_contract(IRolloverVault)11853", + "type": "t_contract(IRolloverVault)11902", "contract": "PerpetualTranche", "src": "contracts/PerpetualTranche.sol:209" } @@ -2751,11 +2751,11 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_contract(IBondController)12129": { + "t_contract(IBondController)12178": { "label": "contract IBondController", "numberOfBytes": "20" }, - "t_contract(IBondIssuer)11490": { + "t_contract(IBondIssuer)11539": { "label": "contract IBondIssuer", "numberOfBytes": "20" }, @@ -2763,15 +2763,15 @@ "label": "contract IERC20Upgradeable", "numberOfBytes": "20" }, - "t_contract(IFeePolicy)11570": { + "t_contract(IFeePolicy)11619": { "label": "contract IFeePolicy", "numberOfBytes": "20" }, - "t_contract(IRolloverVault)11853": { + "t_contract(IRolloverVault)11902": { "label": "contract IRolloverVault", "numberOfBytes": "20" }, - "t_contract(ITranche)12156": { + "t_contract(ITranche)12205": { "label": "contract ITranche", "numberOfBytes": "20" }, @@ -2791,7 +2791,7 @@ "label": "mapping(contract IERC20Upgradeable => uint256)", "numberOfBytes": "32" }, - "t_mapping(t_contract(ITranche)12156,t_uint256)": { + "t_mapping(t_contract(ITranche)12205,t_uint256)": { "label": "mapping(contract ITranche => uint256)", "numberOfBytes": "32" }, @@ -2840,6 +2840,305 @@ }, "namespaces": {} } + }, + "da4c4261b05e9c48f821bf11eb12a2eeae529c35a2152ca2e4794ad6729b13d6": { + "address": "0xA85Be82083E032EdF32a19028DF558484b399196", + "txHash": "0xa4c0c32b4a5756ea10e89753679d3d3485dae0e8ada42fc7cc26633b0f934ec5", + "layout": { + "solcVersion": "0.8.20", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "_balances", + "offset": 0, + "slot": "51", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "52", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "53", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "_name", + "offset": 0, + "slot": "54", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:46" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "55", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:47" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:376" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20BurnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol:51" + }, + { + "label": "_owner", + "offset": 0, + "slot": "151", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" + }, + { + "label": "_paused", + "offset": 0, + "slot": "201", + "type": "t_bool", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" + }, + { + "label": "_status", + "offset": 0, + "slot": "251", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "252", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "underlying", + "offset": 0, + "slot": "301", + "type": "t_contract(IERC20Upgradeable)1205", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:107" + }, + { + "label": "_deployed", + "offset": 0, + "slot": "302", + "type": "t_struct(AddressSet)4926_storage", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:111" + }, + { + "label": "minDeploymentAmt", + "offset": 0, + "slot": "304", + "type": "t_uint256", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:119" + }, + { + "label": "perp", + "offset": 0, + "slot": "305", + "type": "t_contract(IPerpetualTranche)11845", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:122" + }, + { + "label": "feePolicy", + "offset": 0, + "slot": "306", + "type": "t_contract(IFeePolicy)11619", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:128" + }, + { + "label": "keeper", + "offset": 0, + "slot": "307", + "type": "t_address", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:133" + }, + { + "label": "reservedUnderlyingBal", + "offset": 0, + "slot": "308", + "type": "t_uint256", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:144" + }, + { + "label": "reservedSubscriptionPerc", + "offset": 0, + "slot": "309", + "type": "t_uint256", + "contract": "RolloverVault", + "src": "contracts/RolloverVault.sol:152" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(IERC20Upgradeable)1205": { + "label": "contract IERC20Upgradeable", + "numberOfBytes": "20" + }, + "t_contract(IFeePolicy)11619": { + "label": "contract IFeePolicy", + "numberOfBytes": "20" + }, + "t_contract(IPerpetualTranche)11845": { + "label": "contract IPerpetualTranche", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)4926_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)4611_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Set)4611_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } } } } diff --git a/spot-contracts/contracts/FeePolicy.sol b/spot-contracts/contracts/FeePolicy.sol index 7376e105..e3ee29b5 100644 --- a/spot-contracts/contracts/FeePolicy.sol +++ b/spot-contracts/contracts/FeePolicy.sol @@ -2,58 +2,57 @@ pragma solidity ^0.8.20; import { IFeePolicy } from "./_interfaces/IFeePolicy.sol"; -import { SubscriptionParams } from "./_interfaces/CommonTypes.sol"; -import { InvalidPerc, InvalidTargetSRBounds, InvalidDRBounds, InvalidSigmoidAsymptotes } from "./_interfaces/ProtocolErrors.sol"; +import { SubscriptionParams, Range, Line } from "./_interfaces/CommonTypes.sol"; +import { InvalidPerc, InvalidRange, InvalidFees } from "./_interfaces/ProtocolErrors.sol"; +import { LineHelpers } from "./_utils/LineHelpers.sol"; import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; +import { SignedMathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.sol"; import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import { Sigmoid } from "./_utils/Sigmoid.sol"; +import { MathHelpers } from "./_utils/MathHelpers.sol"; /** * @title FeePolicy * - * @notice This contract determines fees for interacting with the perp and vault systems. + * @notice This contract determines fees and incentives for interacting with the perp and vault systems. * * The fee policy attempts to balance the demand for holding perp tokens with - * the demand for holding vault tokens; such that the total collateral in the vault - * supports rolling over all mature collateral backing perps. + * the demand for holding vault tokens; such that the total asset value in the vault + * supports rolling over all mature tranches backing perps. * - * Fees are computed based on the deviation between the system's current subscription ratio - * and the target subscription ratio. + * The system's balance is defined by it's `deviationRatio` which is defined as follows. * - `subscriptionRatio` = (vaultTVL * seniorTR) / (perpTVL * 1-seniorTR) * - `deviationRatio` (dr) = subscriptionRatio / targetSubscriptionRatio * - * When the system is "under-subscribed" (dr <= 1): - * - Rollover fees flow from perp holders to vault note holders. - * - Fees are charged for minting new perps. - * - No fees are charged for redeeming perps. + * When the dr = 1, the system is considered perfectly balanced. + * When the dr < 1, it's considered "under-subscribed". + * When the dr > 1, it's considered "over-subscribed". * - * When the system is "over-subscribed" (dr > 1): - * - Rollover fees flow from vault note holders to perp holders. - * - No fees are charged for minting new perps. - * - Fees are charged for redeeming perps. + * Fees: + * - The system charges a greater fee for operations that move it away from the balance point. + * - If an operation moves the system back to the balance point, it charges a lower fee (or no fee). * - * Regardless of the `deviationRatio`, the system charges a fixed percentage fee - * for minting and redeeming vault notes. + * Incentives: + * - When the system is "under-subscribed", value is transferred from perp to the vault at a predefined rate. + * This debases perp tokens gradually and enriches the rollover vault. + * - When the system is "over-subscribed", value is transferred from the vault to perp at a predefined rate. + * This enriches perp tokens gradually and debases the rollover vault. + * - This transfer is implemented through a periodic "rebalance" operation, executed by the vault, and + * gradually nudges the system back into balance. On rebalance, the vault queries this policy + * to compute the magnitude and direction of value transfer. * - * - * The rollover fees are signed and can flow in either direction based on the `deviationRatio`. - * The fee is a percentage is computed through a sigmoid function. - * The slope and asymptotes are set by the owner. - * - * CRITICAL: The rollover fee percentage is NOT annualized, the fee percentage is applied per rollover. - * The number of rollovers per year changes based on the duration of perp's minting bond. - * - * We consider a `deviationRatio` of greater than 1.0 healthy (or "over-subscribed"). - * In general, the system favors an elastic perp supply and an inelastic vault note supply. + * NOTE: All parameters are stored as fixed point numbers with {DECIMALS} decimal places. * * */ contract FeePolicy is IFeePolicy, OwnableUpgradeable { // Libraries using MathUpgradeable for uint256; + using MathHelpers for uint256; + using SignedMathUpgradeable for int256; using SafeCastUpgradeable for uint256; + using SafeCastUpgradeable for int256; // Replicating value used here: // https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol @@ -65,17 +64,7 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable { uint8 public constant DECIMALS = 8; /// @notice Fixed point representation of 1.0 or 100%. - uint256 public constant ONE = (1 * 10 ** DECIMALS); - - /// @notice Sigmoid asymptote bound. - /// @dev Set to 0.05 or 5%, i.e) the rollover fee can be at most 5% on either direction. - uint256 public constant SIGMOID_BOUND = ONE / 20; - - /// @notice Target subscription ratio lower bound, 0.75 or 75%. - uint256 public constant TARGET_SR_LOWER_BOUND = (ONE * 75) / 100; - - /// @notice Target subscription ratio higher bound, 2.0 or 200%. - uint256 public constant TARGET_SR_UPPER_BOUND = 2 * ONE; + uint256 public constant ONE = (10 ** DECIMALS); //----------------------------------------------------------------------------- /// @notice The target subscription ratio i.e) the normalization factor. @@ -83,51 +72,43 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable { /// Adds a safety buffer to ensure that rollovers are better sustained. uint256 public targetSubscriptionRatio; - /// @notice The lower bound of deviation ratio, below which some operations (which decrease the dr) are disabled. - uint256 public deviationRatioBoundLower; - - /// @notice The upper bound of deviation ratio, above which some operations (which increase the dr) are disabled. - uint256 public deviationRatioBoundUpper; - - //----------------------------------------------------------------------------- + /// @notice The range of deviation ratios which define the equilibrium zone. + /// @dev When the system's dr is within the equilibrium zone, no value is transferred + /// during a rebalance operation. + Range public equilibriumDR; //----------------------------------------------------------------------------- - // Perp fee parameters + // Fee parameters - /// @notice The percentage fee charged on minting perp tokens. - uint256 public perpMintFeePerc; + /// @notice Linear fee function used for operations that decrease DR (x-axis dr, y-axis fees). + Line public feeFnDRDown; - /// @notice The percentage fee charged on burning perp tokens. - uint256 public perpBurnFeePerc; + /// @notice Linear fee function used for operations that increase DR (x-axis dr, y-axis fees). + Line public feeFnDRUp; - struct RolloverFeeSigmoidParams { - /// @notice Lower asymptote - int256 lower; - /// @notice Upper asymptote - int256 upper; - /// @notice sigmoid slope - int256 growth; - } + //----------------------------------------------------------------------------- + // Rebalance parameters - /// @notice Parameters which control the asymptotes and the slope of the perp token's rollover fee. - RolloverFeeSigmoidParams public perpRolloverFee; + /// @notice Reaction lag factor applied to rebalancing on perp debasement. + uint256 public perpDebasementLag; - //----------------------------------------------------------------------------- + /// @notice Reaction lag factor applied to rebalancing on perp enrichment. + uint256 public perpEnrichmentLag; - //----------------------------------------------------------------------------- - // Vault fee parameters + /// @notice Lower and upper percentage limits on perp debasement. + Range public perpDebasementPercLimits; - /// @notice The percentage fee charged on minting vault notes. - uint256 public vaultMintFeePerc; + /// @notice Lower and upper percentage limits on perp enrichment. + Range public perpEnrichmentPercLimits; - /// @notice The percentage fee charged on burning vault notes. - uint256 public vaultBurnFeePerc; + /// @notice Minimum number of seconds between subsequent rebalances. + uint256 public override rebalanceFreqSec; - /// @notice The percentage fee charged by the vault to swap underlying tokens for perp tokens. - uint256 public vaultUnderlyingToPerpSwapFeePerc; + /// @notice The percentage of system tvl charged as protocol fees on every rebalance. + uint256 public override protocolSharePerc; - /// @notice The percentage fee charged by the vault to swap perp tokens for underlying tokens. - uint256 public vaultPerpToUnderlyingSwapFeePerc; + /// @notice The address to which the protocol fees are streamed to. + address public override protocolFeeCollector; //----------------------------------------------------------------------------- @@ -140,24 +121,40 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable { function init() external initializer { __Ownable_init(); - // initializing mint/burn fees to zero - perpMintFeePerc = 0; - perpBurnFeePerc = 0; - vaultMintFeePerc = 0; - vaultBurnFeePerc = 0; - - // initializing swap fees to 100%, to disable swapping initially - vaultUnderlyingToPerpSwapFeePerc = ONE; - vaultPerpToUnderlyingSwapFeePerc = ONE; - - // NOTE: With the current bond length of 28 days, rollover rate is annualized by dividing by: 365/28 ~= 13 - perpRolloverFee.lower = -int256(ONE) / (30 * 13); // -0.033/13 = -0.00253 (3.3% annualized) - perpRolloverFee.upper = int256(ONE) / (10 * 13); // 0.1/13 = 0.00769 (10% annualized) - perpRolloverFee.growth = 5 * int256(ONE); // 5.0 - - targetSubscriptionRatio = (ONE * 133) / 100; // 1.33 - deviationRatioBoundLower = (ONE * 75) / 100; // 0.75 - deviationRatioBoundUpper = 2 * ONE; // 2.0 + targetSubscriptionRatio = (ONE * 150) / 100; // 1.5 + equilibriumDR = Range({ + lower: (ONE * 95) / 100, // 0.95 + upper: (ONE * 105) / 100 // 1.05 + }); + + // initializing fees + feeFnDRDown = Line({ + x1: (ONE * 66) / 100, // 0.66 + y1: ONE / 4, // 25% + x2: (ONE * 95) / 100, // 0.95 + y2: 0 // 0% + }); + feeFnDRUp = Line({ + x1: (ONE * 105) / 100, // 1.05 + y1: 0, // 0% + x2: (ONE * 150) / 100, // 1.5 + y2: ONE / 4 // 25% + }); + + // initializing rebalancing parameters + perpDebasementLag = 30; + perpEnrichmentLag = 30; + perpDebasementPercLimits = Range({ + lower: (ONE) / 200, // 0.5% or 50 bps + upper: ONE / 40 // 2.5% or 250 bps + }); + perpEnrichmentPercLimits = Range({ + lower: (ONE) / 200, // 0.5% or 50 bps + upper: ONE / 40 // 2.5% or 250 bps + }); + rebalanceFreqSec = 86400; // 1 day + protocolSharePerc = ONE / 100; // or 1% + protocolFeeCollector = owner(); } //----------------------------------------------------------------------------- @@ -166,166 +163,177 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable { /// @notice Updates the target subscription ratio. /// @param targetSubscriptionRatio_ The new target subscription ratio as a fixed point number with {DECIMALS} places. function updateTargetSubscriptionRatio(uint256 targetSubscriptionRatio_) external onlyOwner { - if (targetSubscriptionRatio_ < TARGET_SR_LOWER_BOUND || targetSubscriptionRatio_ > TARGET_SR_UPPER_BOUND) { - revert InvalidTargetSRBounds(); - } targetSubscriptionRatio = targetSubscriptionRatio_; } - /// @notice Updates the deviation ratio bounds. - /// @param deviationRatioBoundLower_ The new lower deviation ratio bound as fixed point number with {DECIMALS} places. - /// @param deviationRatioBoundUpper_ The new upper deviation ratio bound as fixed point number with {DECIMALS} places. - function updateDeviationRatioBounds( - uint256 deviationRatioBoundLower_, - uint256 deviationRatioBoundUpper_ - ) external onlyOwner { - if (deviationRatioBoundLower_ > ONE || deviationRatioBoundUpper_ < ONE) { - revert InvalidDRBounds(); + /// @notice Updates the equilibrium DR range. + /// @param equilibriumDR_ The new equilibrium DR range as tuple of a fixed point numbers with {DECIMALS} places. + function updateEquilibriumDR(Range memory equilibriumDR_) external onlyOwner { + if (equilibriumDR_.lower > equilibriumDR_.upper || equilibriumDR_.lower > ONE || equilibriumDR_.upper < ONE) { + revert InvalidRange(); } - deviationRatioBoundLower = deviationRatioBoundLower_; - deviationRatioBoundUpper = deviationRatioBoundUpper_; + equilibriumDR = equilibriumDR_; } - /// @notice Updates the perp mint fee parameters. - /// @param perpMintFeePerc_ The new perp mint fee ceiling percentage - /// as a fixed point number with {DECIMALS} places. - function updatePerpMintFees(uint256 perpMintFeePerc_) external onlyOwner { - if (perpMintFeePerc_ > ONE) { - revert InvalidPerc(); - } - perpMintFeePerc = perpMintFeePerc_; - } + /// @notice Updates the system fee functions. + /// @param feeFnDRDown_ The new fee function for operations that decrease DR. + /// @param feeFnDRUp_ The new fee function for operations that increase DR. + function updateFees(Line memory feeFnDRDown_, Line memory feeFnDRUp_) external onlyOwner { + // Expect DR to be non-decreasing, x1 <= x2 + bool validFees = ((feeFnDRDown_.x1 <= feeFnDRDown_.x2) && (feeFnDRUp_.x1 <= feeFnDRUp_.x2)); - /// @notice Updates the perp burn fee parameters. - /// @param perpBurnFeePerc_ The new perp burn fee ceiling percentage - /// as a fixed point number with {DECIMALS} places. - function updatePerpBurnFees(uint256 perpBurnFeePerc_) external onlyOwner { - if (perpBurnFeePerc_ > ONE) { - revert InvalidPerc(); - } - perpBurnFeePerc = perpBurnFeePerc_; - } + // Expect equilibrium zone to be valid + validFees = ((feeFnDRDown_.x2 <= ONE) && (feeFnDRUp_.x1 >= ONE)) && validFees; - /// @notice Update the parameters determining the slope and asymptotes of the sigmoid fee curve. - /// @param p Lower, Upper and Growth sigmoid paramters are fixed point numbers with {DECIMALS} places. - function updatePerpRolloverFees(RolloverFeeSigmoidParams calldata p) external onlyOwner { - // If the bond duration is 28 days and 13 rollovers happen per year, - // perp can be inflated or enriched up to ~65% annually. - if (p.lower < -int256(SIGMOID_BOUND) || p.upper > int256(SIGMOID_BOUND) || p.lower > p.upper) { - revert InvalidSigmoidAsymptotes(); - } - perpRolloverFee.lower = p.lower; - perpRolloverFee.upper = p.upper; - perpRolloverFee.growth = p.growth; - } + // Expect fees to be non-decreasing when dr moves away from 1.0 + validFees = ((feeFnDRDown_.y1 >= feeFnDRDown_.y2) && (feeFnDRUp_.y1 <= feeFnDRUp_.y2)) && validFees; - /// @notice Updates the vault mint fee parameters. - /// @param vaultMintFeePerc_ The new vault mint fee ceiling percentage - /// as a fixed point number with {DECIMALS} places. - function updateVaultMintFees(uint256 vaultMintFeePerc_) external onlyOwner { - if (vaultMintFeePerc_ > ONE) { - revert InvalidPerc(); - } - vaultMintFeePerc = vaultMintFeePerc_; - } + // Expect fee percentages to be valid + validFees = + (feeFnDRDown_.y1 <= ONE) && + (feeFnDRDown_.y2 <= ONE) && + (feeFnDRUp_.y1 <= ONE) && + ((feeFnDRUp_.y2 <= ONE) && validFees); - /// @notice Updates the vault burn fee parameters. - /// @param vaultBurnFeePerc_ The new vault burn fee ceiling percentage - /// as a fixed point number with {DECIMALS} places. - function updateVaultBurnFees(uint256 vaultBurnFeePerc_) external onlyOwner { - if (vaultBurnFeePerc_ > ONE) { - revert InvalidPerc(); + if (!validFees) { + revert InvalidFees(); } - vaultBurnFeePerc = vaultBurnFeePerc_; + + feeFnDRDown = feeFnDRDown_; + feeFnDRUp = feeFnDRUp_; } - /// @notice Updates the vault's share of the underlying to perp swap fee. - /// @param feePerc The new fee percentage. - function updateVaultUnderlyingToPerpSwapFeePerc(uint256 feePerc) external onlyOwner { - if (feePerc > ONE) { - revert InvalidPerc(); + /// @notice Updates the all the parameters which control magnitude and frequency of the rebalance. + /// @param perpDebasementLag_ The new perp debasement lag factor. + /// @param perpEnrichmentLag_ The new perp enrichment lag factor. + /// @param perpDebasementPercLimits_ The new lower and upper percentage limits on perp debasement. + /// @param perpEnrichmentPercLimits_ The new lower and upper percentage limits on perp enrichment. + /// @param rebalanceFreqSec_ The new rebalance frequency in seconds. + function updateRebalanceConfig( + uint256 perpDebasementLag_, + uint256 perpEnrichmentLag_, + Range memory perpDebasementPercLimits_, + Range memory perpEnrichmentPercLimits_, + uint256 rebalanceFreqSec_ + ) external onlyOwner { + if ( + perpDebasementPercLimits_.lower > perpDebasementPercLimits_.upper || + perpEnrichmentPercLimits_.lower > perpEnrichmentPercLimits_.upper + ) { + revert InvalidRange(); } - vaultUnderlyingToPerpSwapFeePerc = feePerc; + + perpDebasementLag = perpDebasementLag_; + perpEnrichmentLag = perpEnrichmentLag_; + perpDebasementPercLimits = perpDebasementPercLimits_; + perpEnrichmentPercLimits = perpEnrichmentPercLimits_; + rebalanceFreqSec = rebalanceFreqSec_; } - /// @notice Updates the vault's share of the perp to underlying swap fee. - /// @param feePerc The new fee percentage. - function updateVaultPerpToUnderlyingSwapFeePerc(uint256 feePerc) external onlyOwner { - if (feePerc > ONE) { + /// @notice Updates the protocol share of tvl extracted on every rebalance. + /// @param protocolSharePerc_ The share of the tvl which goes to the protocol as a percentage. + /// @param protocolFeeCollector_ The new fee collector address. + function updateProtocolFeeConfig(uint256 protocolSharePerc_, address protocolFeeCollector_) external onlyOwner { + if (protocolSharePerc_ > ONE) { revert InvalidPerc(); } - vaultPerpToUnderlyingSwapFeePerc = feePerc; + protocolSharePerc = protocolSharePerc_; + protocolFeeCollector = protocolFeeCollector_; } //----------------------------------------------------------------------------- // Public methods /// @inheritdoc IFeePolicy - /// @dev Minting perps reduces system dr, i.e) drPost < drPre. - function computePerpMintFeePerc() public view override returns (uint256) { - return perpMintFeePerc; - } - - /// @inheritdoc IFeePolicy - /// @dev Burning perps increases system dr, i.e) drPost > drPre. - function computePerpBurnFeePerc() public view override returns (uint256) { - return perpBurnFeePerc; - } - - /// @inheritdoc IFeePolicy - function computePerpRolloverFeePerc(uint256 dr) external view override returns (int256) { - return - Sigmoid.compute( - dr.toInt256(), - perpRolloverFee.lower, - perpRolloverFee.upper, - perpRolloverFee.growth, - ONE.toInt256() - ); + function computeFeePerc(uint256 drPre, uint256 drPost) public view override returns (uint256) { + // DR is decreasing, we use feeFnDRDown + if (drPre > drPost) { + Line memory fee = feeFnDRDown; + return + LineHelpers + .computePiecewiseAvgY( + fee, + Line({ x1: fee.x2, y1: fee.y2, x2: ONE, y2: fee.y2 }), + Range({ lower: drPost, upper: drPre }), + fee.x2 + ) + .toUint256(); + } + // DR is increasing, we use feeFnDRUp + else { + Line memory fee = feeFnDRUp; + return + LineHelpers + .computePiecewiseAvgY( + Line({ x1: ONE, y1: fee.y1, x2: fee.x1, y2: fee.y1 }), + fee, + Range({ lower: drPre, upper: drPost }), + fee.x1 + ) + .toUint256(); + } } /// @inheritdoc IFeePolicy - /// @dev Minting vault notes increases system dr, i.e) drPost > drPre. - function computeVaultMintFeePerc() external view override returns (uint256) { - return vaultMintFeePerc; + function decimals() external pure override returns (uint8) { + return DECIMALS; } /// @inheritdoc IFeePolicy - function computeVaultBurnFeePerc() external view override returns (uint256) { - return vaultBurnFeePerc; - } + function computeRebalanceAmount( + SubscriptionParams memory s + ) external view override returns (int256 underlyingAmtIntoPerp) { + // We skip rebalancing if dr is close to 1.0 + uint256 dr = computeDeviationRatio(s); + if (dr >= equilibriumDR.lower && dr <= equilibriumDR.upper) { + return 0; + } - /// @inheritdoc IFeePolicy - /// @dev Swapping by minting perps reduces system dr, i.e) drPost < drPre. - function computeUnderlyingToPerpVaultSwapFeePerc( - uint256 /*drPre*/, - uint256 drPost - ) external view override returns (uint256) { - // When the after op deviation ratio is below the bound, - // swapping is disabled. (fees are set to 100%) - return (drPost < deviationRatioBoundLower ? ONE : vaultUnderlyingToPerpSwapFeePerc); - } + // We compute the total value that should flow into perp to push the system into equilibrium. + uint256 totalTVL = s.perpTVL + s.vaultTVL; + uint256 reqPerpTVL = totalTVL.mulDiv(computeDRNormSeniorTR(s.seniorTR), ONE); + int256 reqUnderlyingAmtIntoPerp = reqPerpTVL.toInt256() - s.perpTVL.toInt256(); + + // Perp debasement, value needs to flow from perp into the vault + if (reqUnderlyingAmtIntoPerp < 0) { + // We calculate the 'clipped' lag adjusted rebalance amount + uint256 underlyingAmtTransferred = (reqUnderlyingAmtIntoPerp.abs() / perpDebasementLag).clip( + s.perpTVL.mulDiv(perpDebasementPercLimits.lower, ONE), + s.perpTVL.mulDiv(perpDebasementPercLimits.upper, ONE) + ); - /// @inheritdoc IFeePolicy - /// @dev Swapping by burning perps increases system dr, i.e) drPost > drPre. - function computePerpToUnderlyingVaultSwapFeePerc( - uint256 /*drPre*/, - uint256 drPost - ) external view override returns (uint256) { - // When the after op deviation ratio is above the bound, - // swapping is disabled. (fees are set to 100%) - return (drPost > deviationRatioBoundUpper ? ONE : vaultPerpToUnderlyingSwapFeePerc); - } + // We ensure that the rebalance doesn't overshoot equilibrium + underlyingAmtIntoPerp = SignedMathUpgradeable.max( + -underlyingAmtTransferred.toInt256(), + reqUnderlyingAmtIntoPerp + ); + } + // Perp enrichment, from the vault into perp + else if (reqUnderlyingAmtIntoPerp > 0) { + // We calculate the 'clipped' lag adjusted rebalance amount + uint256 underlyingAmtTransferred = (reqUnderlyingAmtIntoPerp.toUint256() / perpEnrichmentLag).clip( + s.perpTVL.mulDiv(perpEnrichmentPercLimits.lower, ONE), + s.perpTVL.mulDiv(perpEnrichmentPercLimits.upper, ONE) + ); - /// @inheritdoc IFeePolicy - function decimals() external pure override returns (uint8) { - return DECIMALS; + // We ensure that the rebalance doesn't overshoot equilibrium + underlyingAmtIntoPerp = SignedMathUpgradeable.min( + underlyingAmtTransferred.toInt256(), + reqUnderlyingAmtIntoPerp + ); + } } /// @inheritdoc IFeePolicy - function computeDeviationRatio(SubscriptionParams memory s) public view returns (uint256) { + function computeDeviationRatio(SubscriptionParams memory s) public view override returns (uint256) { // NOTE: We assume that perp's TVL and vault's TVL values have the same base denomination. uint256 juniorTR = TRANCHE_RATIO_GRANULARITY - s.seniorTR; return (s.vaultTVL * s.seniorTR).mulDiv(ONE, (s.perpTVL * juniorTR)).mulDiv(ONE, targetSubscriptionRatio); } + + /// @inheritdoc IFeePolicy + function computeDRNormSeniorTR(uint256 seniorTR) public view override returns (uint256) { + uint256 juniorTR = (TRANCHE_RATIO_GRANULARITY - seniorTR); + return ONE.mulDiv((seniorTR * ONE), (seniorTR * ONE) + (juniorTR * targetSubscriptionRatio)); + } } diff --git a/spot-contracts/contracts/PerpetualTranche.sol b/spot-contracts/contracts/PerpetualTranche.sol index 960dfc8e..3028da20 100644 --- a/spot-contracts/contracts/PerpetualTranche.sol +++ b/spot-contracts/contracts/PerpetualTranche.sol @@ -31,11 +31,11 @@ import { BondHelpers } from "./_utils/BondHelpers.sol"; * Users can ONLY mint perps for seniors belonging to the active "deposit" bond. * Users can burn perps, and redeem a proportional share of tokens held in the reserve. * - * Once seniors held in the reserve mature, the underlying collateral is extracted + * Once seniors held in the reserve mature, the underlying token is extracted * into the reserve. At any time, the reserve holds at most 2 classes of tokens - * i.e) the seniors and the underlying collateral. + * i.e) the seniors and the underlying token. * - * Incentivized parties can "rollover" tranches approaching maturity or the underlying collateral, + * The rollover vault can "rollover" tranches approaching maturity or the underlying token, * for newer seniors (which expire further out in the future) that belong to the updated "depositBond". * * @@ -45,6 +45,8 @@ import { BondHelpers } from "./_utils/BondHelpers.sol"; * This brings the system storage state up to date. * * CRITICAL: On the 3 main system operations: deposit, redeem and rollover; + * + * The system charges a fee for minting and burning perp tokens, which are paid to the vault. * We first compute fees before executing any transfers in or out of the system. * The ordering of operations is very important as the fee computation logic, * requires the system TVL as an input and which should be recorded prior to any value @@ -57,6 +59,12 @@ import { BondHelpers } from "./_utils/BondHelpers.sol"; * When computing the value of assets in the system, the code always over-values by * rounding up. When computing the value of incoming assets, the code rounds down. * + * @dev Demand imbalance between perp and the vault + * is restored through a "rebalancing" mechanism similar to a funding rate. When value needs to flow from perp to the vault, + * the system debases the value of perp tokens by minting perp tokens to the vault. + * When value needs to flow from the vault to perp, the fresh senior tranches are + * transferred from the vault into perp's reserve thereby enriching the value of perp tokens. + * */ contract PerpetualTranche is ERC20BurnableUpgradeable, @@ -93,7 +101,7 @@ contract PerpetualTranche is // When `ai` tokens of type `ti` are deposited into the system: // Mint: mintAmt (perps) => (ai * price(ti) / RV) * supply(perps) // - // This ensures that if 10% of the collateral value is deposited, + // This ensures that if 10% of the reserve value is deposited, // the minter receives 10% of the perp token supply. // This removes any race conditions for minters based on reserve state. // @@ -113,7 +121,7 @@ contract PerpetualTranche is uint256 public constant ONE = (10 ** PERC_DECIMALS); // 1.0 or 100% /// @dev The maximum number of reserve assets that can be held by perp. - uint8 public constant MAX_RESERVE_COUNT = 11; + uint8 public constant MAX_RESERVE_COUNT = 21; //------------------------------------------------------------------------- // Storage @@ -161,7 +169,7 @@ contract PerpetualTranche is uint256 public maxTrancheMaturitySec; /// @notice DEPRECATED. - /// @dev This used to control the percentage of the reserve value to be held as the underlying collateral. + /// @dev This used to control the percentage of the reserve value to be held as the underlying token. /// With V2 perp cannot control this anymore, the rollover mechanics are dictated /// by the amount of capital in the vault system. /// @custom:oz-upgrades-renamed-from matureValueTargetPerc @@ -195,7 +203,7 @@ contract PerpetualTranche is EnumerableSetUpgradeable.AddressSet private _reserves; /// @notice DEPRECATED. - /// @dev The used to store the amount of all the mature tranches extracted and held as the collateral token, + /// @dev The used to store the amount of all the mature tranches extracted and held as the underlying token, /// i.e) the reserve's "virtual" mature tranche balance. The system no longer tracks this. // solhint-disable-next-line var-name-mixedcase uint256 private _matureTrancheBalance_DEPRECATED; @@ -244,13 +252,14 @@ contract PerpetualTranche is /// @notice Contract state initialization. /// @param name ERC-20 Name of the Perp token. /// @param symbol ERC-20 Symbol of the Perp token. - /// @param collateral_ Address of the underlying collateral token. + /// @param underlying_ Address of the underlying token. /// @param bondIssuer_ Address of the bond issuer contract. /// @param feePolicy_ Address of the fee policy contract. + /// @dev Call `updateVault` with reference to the rollover vault after initialization. function init( string memory name, string memory symbol, - IERC20Upgradeable collateral_, + IERC20Upgradeable underlying_, IBondIssuer bondIssuer_, IFeePolicy feePolicy_ ) external initializer { @@ -259,18 +268,18 @@ contract PerpetualTranche is __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); - _decimals = IERC20MetadataUpgradeable(address(collateral_)).decimals(); + _decimals = IERC20MetadataUpgradeable(address(underlying_)).decimals(); - // NOTE: `_reserveAt(0)` always points to the underling collateral token + // NOTE: `_reserveAt(0)` always points to the underling underlying token // and is to be never updated. - _reserves.add(address(collateral_)); - _syncReserve(collateral_); + _reserves.add(address(underlying_)); + _syncReserve(underlying_); updateKeeper(owner()); updateFeePolicy(feePolicy_); updateBondIssuer(bondIssuer_); - updateTolerableTrancheMaturity(1, type(uint256).max); + updateTolerableTrancheMaturity(86400 * 7, 86400 * 31); updateMaxSupply(type(uint256).max); updateMaxDepositTrancheValuePerc(ONE); } @@ -347,7 +356,6 @@ contract PerpetualTranche is } /// @notice Unpauses deposits, withdrawals and rollovers. - /// @dev ERC-20 functions, like transfers will always remain operational. function unpause() external onlyKeeper { _unpause(); } @@ -380,9 +388,10 @@ contract PerpetualTranche is revert UnexpectedAsset(); } - // Calculates the fee adjusted amount of perp tokens minted when depositing `trancheInAmt` of tranche tokens - // NOTE: This operation should precede any token transfers. - uint256 perpAmtMint = _computeMintAmt(trancheIn, trancheInAmt); + // Calculates the amount of perp tokens minted when depositing `trancheInAmt` of tranche tokens + // and the perp tokens paid as fees. + // NOTE: This calculation should precede any token transfers. + (uint256 perpAmtMint, uint256 perpFeeAmt) = _computeMintAmt(trancheIn, trancheInAmt); if (trancheInAmt <= 0 || perpAmtMint <= 0) { return 0; } @@ -393,6 +402,9 @@ contract PerpetualTranche is // mints perp tokens to the sender _mint(msg.sender, perpAmtMint); + // Mint fees are collected self-minting perp tokens. + _mint(address(this), perpFeeAmt); + // post-deposit checks _enforceMintCaps(trancheIn); @@ -401,19 +413,22 @@ contract PerpetualTranche is /// @inheritdoc IPerpetualTranche function redeem( - uint256 perpAmtBurnt + uint256 perpAmt ) external override afterStateUpdate nonReentrant whenNotPaused returns (TokenAmount[] memory) { // verifies if burn amount is acceptable - if (perpAmtBurnt <= 0) { + if (perpAmt <= 0) { return new TokenAmount[](0); } // Calculates the fee adjusted share of reserve tokens to be redeemed - // NOTE: This operation should precede any token transfers. - TokenAmount[] memory tokensOut = _computeRedemptionAmts(perpAmtBurnt); + // NOTE: This calculation should precede any token transfers. + (TokenAmount[] memory tokensOut, uint256 perpFeeAmt) = _computeRedemptionAmts(perpAmt); // burns perp tokens from the sender - _burn(msg.sender, perpAmtBurnt); + _burn(msg.sender, perpAmt - perpFeeAmt); + + // Redemption fees are collected by transferring some perp tokens from the user. + transfer(address(this), perpFeeAmt); // transfers reserve tokens out uint8 tokensOutCount = uint8(tokensOut.length); @@ -437,8 +452,8 @@ contract PerpetualTranche is revert UnacceptableRollover(); } - // Calculates the fee adjusted amount of tranches exchanged during a rolled over - // NOTE: This operation should precede any token transfers. + // Calculates the amount of tranches exchanged during a rolled over + // NOTE: This calculation should precede any token transfers. RolloverData memory r = _computeRolloverAmt(trancheIn, tokenOut, trancheInAmtAvailable); // Verifies if rollover amount is acceptable @@ -455,6 +470,45 @@ contract PerpetualTranche is return r; } + /// @inheritdoc IPerpetualTranche + /// @dev Only the whitelisted vault can call this function. + function claimFees(address to) external override onlyVault nonReentrant whenNotPaused { + IERC20Upgradeable perp_ = IERC20Upgradeable(address(this)); + uint256 collectedBal = perp_.balanceOf(address(perp_)); + if (collectedBal > 0) { + perp_.safeTransfer(to, collectedBal); + } + } + + /// @inheritdoc IPerpetualTranche + /// @dev Only the whitelisted vault can call this function. + function payProtocolFee( + address collector, + uint256 protocolSharePerc + ) external override onlyVault nonReentrant whenNotPaused { + if (protocolSharePerc > 0) { + _mint(collector, protocolSharePerc.mulDiv(totalSupply(), ONE - protocolSharePerc)); + } + } + + /// @inheritdoc IPerpetualTranche + /// @dev Only the whitelisted vault can call this function. + /// The logic controlling the frequency and magnitude of debasement should be vetted. + function rebalanceToVault( + uint256 underlyingAmtToTransfer + ) external override onlyVault afterStateUpdate nonReentrant whenNotPaused { + // When value is flowing out of perp to the vault, + // we mint the vault perp tokens. + if (underlyingAmtToTransfer > 0) { + uint256 perpAmtToVault = underlyingAmtToTransfer.mulDiv( + totalSupply(), + _reserveValue() - underlyingAmtToTransfer, + MathUpgradeable.Rounding.Up + ); + _mint(address(vault), perpAmtToVault); + } + } + /// @inheritdoc IPerpetualTranche function getDepositBond() external override afterStateUpdate returns (IBondController) { return _depositBond; @@ -522,7 +576,7 @@ contract PerpetualTranche is // We count the number of tokens up for rollover. uint8 numTokensUpForRollover = 0; - // If any underlying collateral exists it can be rolled over. + // If any underlying token exists it can be rolled over. IERC20Upgradeable underlying_ = _reserveAt(0); if (underlying_.balanceOf(address(this)) > 0) { activeRolloverTokens[0] = underlying_; @@ -551,7 +605,7 @@ contract PerpetualTranche is } /// @inheritdoc IPerpetualTranche - /// @dev Returns a fixed point with the same decimals as the underlying collateral. + /// @dev Returns a fixed point with the same decimals as the underlying token. function getTVL() external override afterStateUpdate returns (uint256) { return _reserveValue(); } @@ -564,14 +618,14 @@ contract PerpetualTranche is if (!_isDepositTranche(trancheIn)) { revert UnexpectedAsset(); } - return _computeMintAmt(trancheIn, trancheInAmt); + (uint256 perpAmtMint, ) = _computeMintAmt(trancheIn, trancheInAmt); + return perpAmtMint; } /// @inheritdoc IPerpetualTranche - function computeRedemptionAmts( - uint256 perpAmtBurnt - ) external override afterStateUpdate returns (TokenAmount[] memory) { - return _computeRedemptionAmts(perpAmtBurnt); + function computeRedemptionAmts(uint256 perpAmt) external override afterStateUpdate returns (TokenAmount[] memory) { + (TokenAmount[] memory tokensOut, ) = _computeRedemptionAmts(perpAmt); + return tokensOut; } /// @inheritdoc IPerpetualTranche @@ -588,14 +642,7 @@ contract PerpetualTranche is /// @inheritdoc IPerpetualTranche function deviationRatio() external override afterStateUpdate nonReentrant returns (uint256) { - return - feePolicy.computeDeviationRatio( - SubscriptionParams({ - perpTVL: _reserveValue(), - vaultTVL: vault.getTVL(), - seniorTR: _depositBond.getSeniorTrancheRatio() - }) - ); + return feePolicy.computeDeviationRatio(_querySubscriptionState()); } //-------------------------------------------------------------------------- @@ -623,12 +670,12 @@ contract PerpetualTranche is } // Lazily checks if every reserve tranche has reached maturity. - // If so redeems the tranche balance for the underlying collateral and + // If so redeems the tranche balance for the underlying token and // removes the tranche from the reserve set. // NOTE: We traverse the reserve set in the reverse order // as deletions involve swapping the deleted element to the // end of the set and removing the last element. - // We also skip the `reserveAt(0)`, i.e) the underlying collateral, + // We also skip the `reserveAt(0)`, i.e) the underlying token, // which is never removed. uint8 reserveCount = uint8(_reserves.length()); for (uint8 i = reserveCount - 1; i > 0; i--) { @@ -645,12 +692,12 @@ contract PerpetualTranche is bond.mature(); } - // Redeeming the underlying collateral token + // Redeeming the underlying token bond.redeemMature(address(tranche), tranche.balanceOf(address(this))); _syncReserve(tranche); } - // Keeps track of the underlying collateral balance + // Keeps track of the underlying token balance _syncReserve(_reserveAt(0)); } @@ -695,7 +742,7 @@ contract PerpetualTranche is uint256 balance = token.balanceOf(address(this)); emit ReserveSynced(token, balance); - // The underlying collateral NEVER gets removed from the `_reserves` set. + // The underlying token NEVER gets removed from the `_reserves` set. if (_isUnderlying(token)) { return balance; } @@ -724,7 +771,10 @@ contract PerpetualTranche is } /// @dev Computes the fee adjusted perp mint amount for given amount of tranche tokens deposited into the reserve. - function _computeMintAmt(ITranche trancheIn, uint256 trancheInAmt) private view returns (uint256) { + function _computeMintAmt( + ITranche trancheIn, + uint256 trancheInAmt + ) private view returns (uint256 perpAmtMint, uint256 perpFeeAmt) { uint256 valueIn = _computeReserveTrancheValue( trancheIn, _depositBond, @@ -735,72 +785,80 @@ contract PerpetualTranche is //----------------------------------------------------------------------------- // We charge no mint fee when interacting with other callers within the system. - uint256 feePerc = _isProtocolCaller() ? 0 : feePolicy.computePerpMintFeePerc(); + SubscriptionParams memory s = _querySubscriptionState(); + uint256 feePerc = _isProtocolCaller() + ? 0 + : feePolicy.computeFeePerc( + feePolicy.computeDeviationRatio(s), + feePolicy.computeDeviationRatio( + SubscriptionParams({ perpTVL: s.perpTVL + valueIn, vaultTVL: s.vaultTVL, seniorTR: s.seniorTR }) + ) + ); //----------------------------------------------------------------------------- // Compute mint amt uint256 perpSupply = totalSupply(); - uint256 perpAmtMint = valueIn; + perpAmtMint = valueIn; if (perpSupply > 0) { perpAmtMint = perpAmtMint.mulDiv(perpSupply, _reserveValue()); } - // The mint fees are settled by simply minting fewer perps. + // Compute the fee amount if (feePerc > 0) { - perpAmtMint = perpAmtMint.mulDiv(ONE - feePerc, ONE); + perpFeeAmt = perpAmtMint.mulDiv(feePerc, ONE, MathUpgradeable.Rounding.Up); + perpAmtMint -= perpFeeAmt; } - - return perpAmtMint; } /// @dev Computes the reserve token amounts redeemed when a given number of perps are burnt. - function _computeRedemptionAmts(uint256 perpAmtBurnt) private view returns (TokenAmount[] memory) { + function _computeRedemptionAmts( + uint256 perpAmt + ) private view returns (TokenAmount[] memory reserveTokens, uint256 perpFeeAmt) { uint256 perpSupply = totalSupply(); //----------------------------------------------------------------------------- // We charge no burn fee when interacting with other parts of the system. - uint256 feePerc = _isProtocolCaller() ? 0 : feePolicy.computePerpBurnFeePerc(); + SubscriptionParams memory s = _querySubscriptionState(); + uint256 feePerc = _isProtocolCaller() + ? 0 + : feePolicy.computeFeePerc( + feePolicy.computeDeviationRatio(s), + feePolicy.computeDeviationRatio( + SubscriptionParams({ + perpTVL: s.perpTVL.mulDiv(perpSupply - perpAmt, perpSupply), + vaultTVL: s.vaultTVL, + seniorTR: s.seniorTR + }) + ) + ); //----------------------------------------------------------------------------- + // Compute the fee amount + if (feePerc > 0) { + perpFeeAmt = perpAmt.mulDiv(feePerc, ONE, MathUpgradeable.Rounding.Up); + perpAmt -= perpFeeAmt; + } + // Compute redemption amounts uint8 reserveCount = uint8(_reserves.length()); - TokenAmount[] memory reserveTokens = new TokenAmount[](reserveCount); + reserveTokens = new TokenAmount[](reserveCount); for (uint8 i = 0; i < reserveCount; ++i) { IERC20Upgradeable tokenOut = _reserveAt(i); reserveTokens[i] = TokenAmount({ token: tokenOut, - amount: tokenOut.balanceOf(address(this)).mulDiv(perpAmtBurnt, perpSupply) + amount: tokenOut.balanceOf(address(this)).mulDiv(perpAmt, perpSupply) }); - - // The burn fees are settled by simply redeeming for fewer tranches. - if (feePerc > 0) { - reserveTokens[i].amount = reserveTokens[i].amount.mulDiv(ONE - feePerc, ONE); - } } - return (reserveTokens); + return (reserveTokens, perpFeeAmt); } /// @dev Computes the amount of reserve tokens that can be rolled out for the given amount of tranches deposited. - /// The relative ratios of tokens In/Out are adjusted based on the current rollover fee perc. function _computeRolloverAmt( ITranche trancheIn, IERC20Upgradeable tokenOut, uint256 trancheInAmtAvailable - ) private view returns (RolloverData memory) { - //----------------------------------------------------------------------------- - // The rollover fees are settled by, adjusting the exchange rate - // between `trancheInAmt` and `tokenOutAmt`. - // - int256 feePerc = feePolicy.computePerpRolloverFeePerc( - feePolicy.computeDeviationRatio( - SubscriptionParams({ - perpTVL: _reserveValue(), - vaultTVL: vault.getTVL(), - seniorTR: _depositBond.getSeniorTrancheRatio() - }) - ) - ); + ) private view returns (RolloverData memory r) { //----------------------------------------------------------------------------- // We compute "price" as the value of a unit token. @@ -829,61 +887,34 @@ contract PerpetualTranche is uint256 tokenOutBalance = tokenOut.balanceOf(address(this)); if (trancheInAmtAvailable <= 0 || tokenOutBalance <= 0 || trancheInPrice <= 0 || tokenOutPrice <= 0) { - return RolloverData({ trancheInAmt: 0, tokenOutAmt: 0 }); + return r; } + //----------------------------------------------------------------------------- - // Basic rollover with fees: - // (1 +/- f) . (trancheInAmt . trancheInPrice) = (tokenOutAmt . tokenOutPrice) + // Basic rollover: + // (trancheInAmt . trancheInPrice) = (tokenOutAmt . tokenOutPrice) //----------------------------------------------------------------------------- // Using perp's tokenOutBalance, we calculate the amount of tokens in to rollover // the entire balance. - - RolloverData memory r = RolloverData({ - tokenOutAmt: tokenOutBalance, - trancheInAmt: tokenOutBalance.mulDiv(tokenOutPrice, trancheInPrice, MathUpgradeable.Rounding.Up) - }); - - // A positive fee percentage implies that perp charges rotators by - // offering tranchesOut for a premium, i.e) more tranches in. - if (feePerc > 0) { - r.trancheInAmt = r.trancheInAmt.mulDiv(ONE, ONE - feePerc.toUint256(), MathUpgradeable.Rounding.Up); - } - // A negative fee percentage (or a reward) implies that perp pays the rotators by - // offering tranchesOut at a discount, i.e) fewer tranches in. - else if (feePerc < 0) { - r.trancheInAmt = r.trancheInAmt.mulDiv(ONE, ONE + feePerc.abs(), MathUpgradeable.Rounding.Up); - } + r.tokenOutAmt = tokenOutBalance; + r.trancheInAmt = tokenOutBalance.mulDiv(tokenOutPrice, trancheInPrice, MathUpgradeable.Rounding.Up); //----------------------------------------------------------------------------- // When the trancheInAmt exceeds trancheInAmtAvailable: // we fix trancheInAmt = trancheInAmtAvailable and re-calculate tokenOutAmt - if (r.trancheInAmt > trancheInAmtAvailable) { // Given the amount of tranches In, we compute the amount of tokens out r.trancheInAmt = trancheInAmtAvailable; r.tokenOutAmt = trancheInAmtAvailable.mulDiv(trancheInPrice, tokenOutPrice); - - // A positive fee percentage implies that perp charges rotators by - // accepting tranchesIn at a discount, i.e) fewer tokens out. - // This results in perp enrichment. - if (feePerc > 0) { - r.tokenOutAmt = r.tokenOutAmt.mulDiv(ONE - feePerc.abs(), ONE); - } - // A negative fee percentage (or a reward) implies that perp pays the rotators by - // accepting tranchesIn at a premium, i.e) more tokens out. - // This results in perp debasement. - else if (feePerc < 0) { - r.tokenOutAmt = r.tokenOutAmt.mulDiv(ONE + feePerc.abs(), ONE); - } } return r; } /// @dev Checks if the given token pair is a valid rollover. - /// * When rolling out underlying collateral, + /// * When rolling out underlying token, /// - expects incoming tranche to be part of the deposit bond /// * When rolling out immature tranches, /// - expects incoming tranche to be part of the deposit bond @@ -891,7 +922,7 @@ contract PerpetualTranche is /// - expects outgoing tranche to be in the reserve /// - expects outgoing tranche to be ready for rollout. function _isAcceptableRollover(ITranche trancheIn, IERC20Upgradeable tokenOut) private view returns (bool) { - // when rolling out the underlying collateral + // when rolling out the underlying token if (_isUnderlying(tokenOut)) { return _isDepositTranche(trancheIn); } @@ -905,7 +936,7 @@ contract PerpetualTranche is } /// @dev Checks if the given bond is valid and can be accepted into the reserve. - /// * Expects the bond to to have the same collateral token as perp. + /// * Expects the bond to to have the same underlying token as perp. /// * Expects the bond to have only two tranches. /// * Expects the bond controller to not withhold any fees. /// * Expects the bond's time to maturity to be within the max safety bound. @@ -944,7 +975,7 @@ contract PerpetualTranche is // Checks if the value of deposit tranche relative to the other tranches in the reserve // is no higher than the defined limit. // - // NOTE: We consider the tranches which are up for rollover and mature collateral (if any), + // NOTE: We consider the tranches which are up for rollover and mature tranches (if any), // to be part of the deposit tranche, as given enough time // they will be eventually rolled over into the deposit tranche. IERC20Upgradeable underlying_ = _reserveAt(0); @@ -982,7 +1013,7 @@ contract PerpetualTranche is } /// @dev Calculates the total value of all the tranches in the reserve. - /// Value of each reserve tranche is denominated in the underlying collateral. + /// Value of each reserve tranche is denominated in the underlying token. function _reserveValue() private view returns (uint256) { IERC20Upgradeable underlying_ = _reserveAt(0); uint256 totalVal = underlying_.balanceOf(address(this)); @@ -1007,12 +1038,12 @@ contract PerpetualTranche is function _computeReserveTrancheValue( ITranche tranche, IBondController parentBond, - IERC20Upgradeable collateralToken, + IERC20Upgradeable underlying_, uint256 trancheAmt, MathUpgradeable.Rounding rounding ) private view returns (uint256) { // NOTE: As an optimization here, we assume that the reserve tranche is immature and has the most senior claim. - uint256 parentBondCollateralBalance = collateralToken.balanceOf(address(parentBond)); + uint256 parentBondCollateralBalance = underlying_.balanceOf(address(parentBond)); uint256 trancheSupply = tranche.totalSupply(); uint256 trancheClaim = MathUpgradeable.min(trancheSupply, parentBondCollateralBalance); // Tranche supply is zero (its parent bond has no deposits yet); @@ -1020,7 +1051,17 @@ contract PerpetualTranche is return (trancheSupply > 0) ? trancheClaim.mulDiv(trancheAmt, trancheSupply, rounding) : trancheAmt; } - /// @dev Checks if the given token is the underlying collateral token. + /// @dev Queries the current subscription state of the perp and vault systems. + function _querySubscriptionState() private view returns (SubscriptionParams memory) { + return + SubscriptionParams({ + perpTVL: _reserveValue(), + vaultTVL: vault.getTVL(), + seniorTR: _depositBond.getSeniorTrancheRatio() + }); + } + + /// @dev Checks if the given token is the underlying token. function _isUnderlying(IERC20Upgradeable token) private view returns (bool) { return (token == _reserveAt(0)); } diff --git a/spot-contracts/contracts/RolloverVault.sol b/spot-contracts/contracts/RolloverVault.sol index c17c8478..b5b2f71b 100644 --- a/spot-contracts/contracts/RolloverVault.sol +++ b/spot-contracts/contracts/RolloverVault.sol @@ -6,12 +6,14 @@ import { IVault } from "./_interfaces/IVault.sol"; import { IRolloverVault } from "./_interfaces/IRolloverVault.sol"; import { IERC20Burnable } from "./_interfaces/IERC20Burnable.sol"; import { TokenAmount, RolloverData, SubscriptionParams } from "./_interfaces/CommonTypes.sol"; -import { UnauthorizedCall, UnauthorizedTransferOut, UnexpectedDecimals, UnexpectedAsset, OutOfBounds, UnacceptableSwap, InsufficientDeployment, DeployedCountOverLimit, InsufficientLiquidity } from "./_interfaces/ProtocolErrors.sol"; +import { UnauthorizedCall, UnauthorizedTransferOut, UnexpectedDecimals, UnexpectedAsset, OutOfBounds, UnacceptableSwap, InsufficientDeployment, DeployedCountOverLimit, InsufficientLiquidity, LastRebalanceTooRecent } from "./_interfaces/ProtocolErrors.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; +import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; +import { SignedMathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.sol"; import { ERC20BurnableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; import { EnumerableSetUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; @@ -19,12 +21,17 @@ import { BondTranches, BondTranchesHelpers } from "./_utils/BondTranchesHelpers. import { TrancheHelpers } from "./_utils/TrancheHelpers.sol"; import { BondHelpers } from "./_utils/BondHelpers.sol"; import { PerpHelpers } from "./_utils/PerpHelpers.sol"; +import { ERC20Helpers } from "./_utils/ERC20Helpers.sol"; +import { TrancheManager } from "./_utils/TrancheManager.sol"; /* * @title RolloverVault * - * @notice A vault which generates yield (from fees) by performing rollovers on PerpetualTranche (or perp). - * The vault takes in AMPL or any other rebasing collateral as the "underlying" asset. + * @notice A vault which performs rollovers on PerpetualTranche (or perp). After rolling over, + * it holds the junior tranches to maturity, effectively becoming a perpetual junior tranche. + * + * The vault takes in AMPL or any other rebasing token as the "underlying" asset. + * It also generates a yield (from entry/exit fees, flash swap liquidity, and rebalancing incentives). * * Vault strategy: * 1) deploy: The vault deposits the underlying asset into perp's current deposit bond @@ -33,9 +40,14 @@ import { PerpHelpers } from "./_utils/PerpHelpers.sol"; * 2) recover: The vault redeems the tranches it holds for the underlying asset. * NOTE: It performs both mature and immature redemption. Read more: https://bit.ly/3tuN6OC * - * With v2.0, vault provides perp<>underlying swap liquidity and charges a fee. + * The vault provides perp<>underlying swap liquidity and charges a fee. * The swap fees are an additional source of yield for vault note holders. * + * The vault has a "rebalance" operation (which can be executed at most once a day). + * This is intended to balance demand for holding perp tokens with + * the demand for holding vault notes, such that the vault is always sufficiently capitalized. + * + * * @dev When new tranches are added into the system, always double check if they are not malicious * by only accepting one whitelisted by perp (ones part of perp's deposit bond or ones part of the perp reserve). * @@ -43,6 +55,12 @@ import { PerpHelpers } from "./_utils/PerpHelpers.sol"; * When ever a tranche token enters or leaves the system, we immediately invoke `_syncDeployedAsset` to update book-keeping. * We call `_syncAsset` at the very end of every external function which changes the vault's underlying or perp balance. * + * The perp tokens aren't considered be part of the vault's asset set. However + * during the normal operations, the vault can hold transient perp tokens but they + * are immediately broken down into tranches. The vault receives perps only during rebalancing and swapping. + * At the end of those operations, the vault redeems perp tokens for the senior tranches backing them. + * + * */ contract RolloverVault is ERC20BurnableUpgradeable, @@ -59,9 +77,16 @@ contract RolloverVault is // ERC20 operations using SafeERC20Upgradeable for IERC20Upgradeable; + using SafeERC20Upgradeable for ITranche; + using ERC20Helpers for IERC20Upgradeable; // math using MathUpgradeable for uint256; + using SignedMathUpgradeable for int256; + using SafeCastUpgradeable for int256; + + /// Allow linking TrancheManager + /// @custom:oz-upgrades-unsafe-allow external-library-linking //------------------------------------------------------------------------- // Events @@ -102,7 +127,6 @@ contract RolloverVault is // => { [underlying] U _deployed } // // - /// @notice The ERC20 token that can be deposited into this vault. IERC20Upgradeable public underlying; @@ -111,7 +135,7 @@ contract RolloverVault is EnumerableSetUpgradeable.AddressSet private _deployed; //------------------------------------------------------------------------- - // Storage + // Parameters /// @notice Minimum amount of underlying assets that must be deployed, for a deploy operation to succeed. /// @dev The deployment transaction reverts, if the vaults does not have sufficient underlying tokens @@ -151,6 +175,12 @@ contract RolloverVault is /// @custom:oz-upgrades-renamed-from minUnderlyingPerc uint256 public reservedSubscriptionPerc; + //-------------------------------------------------------------------------- + // v3.0.0 STORAGE ADDITION + + /// @notice Recorded timestamp of the last successful rebalance. + uint256 public lastRebalanceTimestampSec; + //-------------------------------------------------------------------------- // Modifiers @@ -188,7 +218,7 @@ contract RolloverVault is __Pausable_init(); __ReentrancyGuard_init(); - // setup underlying collateral + // setup underlying token underlying = perp_.underlying(); // set reference to perp @@ -204,6 +234,7 @@ contract RolloverVault is minDeploymentAmt = 0; reservedUnderlyingBal = 0; reservedSubscriptionPerc = 0; + lastRebalanceTimestampSec = block.timestamp; // sync underlying _syncAsset(underlying); @@ -253,27 +284,42 @@ contract RolloverVault is _unpause(); } - /// @notice Updates the minimum deployment amount requirement. - /// @param minDeploymentAmt_ The new minimum deployment amount, denominated in underlying tokens. - function updateMinDeploymentAmt(uint256 minDeploymentAmt_) external onlyKeeper { - minDeploymentAmt = minDeploymentAmt_; + /// @notice Pauses the rebalance operation. + function pauseRebalance() external onlyKeeper { + lastRebalanceTimestampSec = type(uint64).max; } - /// @notice Updates absolute reserved underlying balance. - /// @param reservedUnderlyingBal_ The new reserved underlying balance. - function updateReservedUnderlyingBal(uint256 reservedUnderlyingBal_) external onlyKeeper { - reservedUnderlyingBal = reservedUnderlyingBal_; + /// @notice Unpauses the rebalance operation. + function unpauseRebalance() external onlyKeeper { + lastRebalanceTimestampSec = block.timestamp; } - /// @notice Updates the reserved subscription percentage. + /// @notice Updates the vault's minimum liquidity requirements. + /// @param minDeploymentAmt_ The new minimum deployment amount, denominated in underlying tokens. + /// @param reservedUnderlyingBal_ The new reserved underlying balance. /// @param reservedSubscriptionPerc_ The new reserved subscription percentage. - function updateReservedSubscriptionPerc(uint256 reservedSubscriptionPerc_) external onlyKeeper { + function updateLiquidityLimits( + uint256 minDeploymentAmt_, + uint256 reservedUnderlyingBal_, + uint256 reservedSubscriptionPerc_ + ) external onlyKeeper { + minDeploymentAmt = minDeploymentAmt_; + reservedUnderlyingBal = reservedUnderlyingBal_; reservedSubscriptionPerc = reservedSubscriptionPerc_; } //-------------------------------------------------------------------------- // External & Public write methods + /// @inheritdoc IRolloverVault + function rebalance() external override nonReentrant whenNotPaused { + if (block.timestamp <= lastRebalanceTimestampSec + feePolicy.rebalanceFreqSec()) { + revert LastRebalanceTooRecent(); + } + _rebalance(perp, underlying); + lastRebalanceTimestampSec = block.timestamp; + } + /// @inheritdoc IVault /// @dev Simply batches the `recover` and `deploy` functions. Reverts if there are no funds to deploy. function recoverAndRedeploy() external override { @@ -316,11 +362,6 @@ contract RolloverVault is function recover() public override nonReentrant whenNotPaused { // Redeem deployed tranches uint8 deployedCount_ = uint8(_deployed.length()); - if (deployedCount_ <= 0) { - return; - } - - // execute redemption on each deployed asset for (uint8 i = 0; i < deployedCount_; ++i) { ITranche tranche = ITranche(_deployed.at(i)); uint256 trancheBalance = tranche.balanceOf(address(this)); @@ -338,7 +379,7 @@ contract RolloverVault is // if bond has matured, redeem the tranche token if (bond.secondsToMaturity() <= 0) { // execute redemption - _execMatureTrancheRedemption(bond, tranche, trancheBalance); + TrancheManager.execMatureTrancheRedemption(bond, tranche, trancheBalance); } // if not redeem using proportional balances // redeems this tranche and it's siblings if the vault holds balances. @@ -347,7 +388,7 @@ contract RolloverVault is // We also skip if the tranche balance is too low as immature redemption will be a no-op. else if (tranche == bt.tranches[0] && trancheBalance > TRANCHE_DUST_AMT) { // execute redemption - _execImmatureTrancheRedemption(bond, bt); + TrancheManager.execImmatureTrancheRedemption(bond, bt); } } @@ -373,49 +414,163 @@ contract RolloverVault is IPerpetualTranche perp_ = perp; if (address(token) == address(perp_)) { - // In case the vault holds perp tokens after swaps or if transferred in erroneously, - // anyone can execute this function to recover perps into tranches. - // This is not part of the regular recovery flow. _meldPerps(perp_); _syncAsset(perp_); _syncAsset(underlying); return; } + revert UnexpectedAsset(); } + /// @inheritdoc IRolloverVault + /// @dev This operation pushes the system back into balance, we thus charge no fees. + function mint2( + uint256 underlyingAmtIn + ) external override nonReentrant whenNotPaused returns (uint256 perpAmt, uint256 vaultNoteAmt) { + IPerpetualTranche perp_ = perp; + IERC20Upgradeable underlying_ = underlying; + + // Compute perp vault asset split. + SubscriptionParams memory s = _querySubscriptionState(perp_); + uint256 underlyingAmtIntoPerp = feePolicy.computeDRNormSeniorTR(s.seniorTR).mulDiv(underlyingAmtIn, ONE); + uint256 underlyingAmtIntoVault = underlyingAmtIn - underlyingAmtIntoPerp; + + // Compute perp amount and vault note amount to mint + perpAmt = underlyingAmtIntoPerp.mulDiv(perp_.totalSupply(), s.perpTVL); + vaultNoteAmt = computeMintAmt(underlyingAmtIntoVault, 0); + + // Transfer underlying tokens from user + underlying_.safeTransferFrom(msg.sender, address(this), underlyingAmtIn); + + // Mint perps to user + _trancheAndMintPerps(perp_, underlying_, s.perpTVL, s.seniorTR, perpAmt); + IERC20Upgradeable(address(perp_)).safeTransfer(msg.sender, perpAmt); + + // Mint vault notes to user + _mint(msg.sender, vaultNoteAmt); + + // Sync underlying + _syncAsset(underlying_); + } + + /// @inheritdoc IRolloverVault + /// @dev This operation maintains the system's balance, we thus charge no fees. + function redeem2( + uint256 perpAmtAvailable, + uint256 vaultNoteAmtAvailable + ) + external + override + nonReentrant + whenNotPaused + returns (uint256 perpAmt, uint256 vaultNoteAmt, TokenAmount[] memory returnedTokens) + { + IPerpetualTranche perp_ = perp; + + // Compute perp vault split + { + uint256 perpSupply = perp_.totalSupply(); + uint256 vaultNoteSupply = totalSupply(); + perpAmt = perpAmtAvailable; + vaultNoteAmt = vaultNoteSupply.mulDiv(perpAmtAvailable, perpSupply); + if (vaultNoteAmt > vaultNoteAmtAvailable) { + vaultNoteAmt = vaultNoteAmtAvailable; + perpAmt = perpSupply.mulDiv(vaultNoteAmtAvailable, vaultNoteSupply); + } + } + + // Redeem vault notes + TokenAmount[] memory vaultTokens = computeRedemptionAmts(vaultNoteAmt, 0); + _burn(msg.sender, vaultNoteAmt); + + // Transfer perps from user and redeem + IERC20Upgradeable(address(perp_)).safeTransferFrom(msg.sender, address(this), perpAmt); + TokenAmount[] memory perpTokens = perp.redeem(perpAmt); + + // Compute final list of tokens to return to the user + // assert(underlying == perpTokens[0].token && underlying == vaultTokens[0].token); + returnedTokens = new TokenAmount[](perpTokens.length + vaultTokens.length - 1); + returnedTokens[0] = TokenAmount({ + token: perpTokens[0].token, + amount: (perpTokens[0].amount + vaultTokens[0].amount) + }); + returnedTokens[0].token.safeTransfer(msg.sender, returnedTokens[0].amount); + + // perp tokens + for (uint8 i = 1; i < uint8(perpTokens.length); i++) { + returnedTokens[i] = perpTokens[i]; + perpTokens[i].token.safeTransfer(msg.sender, returnedTokens[i].amount); + } + + // vault tokens + for (uint8 i = 1; i < uint8(vaultTokens.length); i++) { + returnedTokens[i - 1 + perpTokens.length] = vaultTokens[i]; + vaultTokens[i].token.safeTransfer(msg.sender, vaultTokens[i].amount); + + // sync balances + _syncDeployedAsset(vaultTokens[i].token); + } + + // sync underlying + _syncAsset(returnedTokens[0].token); + } + /// @inheritdoc IVault function deposit(uint256 underlyingAmtIn) external override nonReentrant whenNotPaused returns (uint256) { - // Calculates the fee adjusted amount of notes minted when depositing `underlyingAmtIn` of underlying tokens. + // Compute the mint fees + SubscriptionParams memory s = _querySubscriptionState(perp); + uint256 feePerc = feePolicy.computeFeePerc( + feePolicy.computeDeviationRatio(s), + feePolicy.computeDeviationRatio( + SubscriptionParams({ perpTVL: s.perpTVL, vaultTVL: s.vaultTVL + underlyingAmtIn, seniorTR: s.seniorTR }) + ) + ); + + // Calculates the fee adjusted amount of vault notes minted when depositing `underlyingAmtIn` of underlying tokens. // NOTE: This operation should precede any token transfers. - uint256 notes = computeMintAmt(underlyingAmtIn); - if (underlyingAmtIn <= 0 || notes <= 0) { + uint256 vaultNoteAmt = computeMintAmt(underlyingAmtIn, feePerc); + if (underlyingAmtIn <= 0 || vaultNoteAmt <= 0) { return 0; } // transfer user assets in underlying.safeTransferFrom(msg.sender, address(this), underlyingAmtIn); - // mint notes - _mint(msg.sender, notes); + // mint vault notes + _mint(msg.sender, vaultNoteAmt); // sync underlying _syncAsset(underlying); - return notes; + return vaultNoteAmt; } /// @inheritdoc IVault - function redeem(uint256 notes) public override nonReentrant whenNotPaused returns (TokenAmount[] memory) { - if (notes <= 0) { + function redeem(uint256 vaultNoteAmt) public override nonReentrant whenNotPaused returns (TokenAmount[] memory) { + if (vaultNoteAmt <= 0) { return new TokenAmount[](0); } + // Compute the redemption fees + SubscriptionParams memory s = _querySubscriptionState(perp); + uint256 vaultNoteSupply = totalSupply(); + uint256 feePerc = feePolicy.computeFeePerc( + feePolicy.computeDeviationRatio(s), + feePolicy.computeDeviationRatio( + SubscriptionParams({ + perpTVL: s.perpTVL, + vaultTVL: s.vaultTVL.mulDiv(vaultNoteSupply - vaultNoteAmt, vaultNoteSupply), + seniorTR: s.seniorTR + }) + ) + ); + // Calculates the fee adjusted share of vault tokens to be redeemed // NOTE: This operation should precede any token transfers. - TokenAmount[] memory redemptions = computeRedemptionAmts(notes); + TokenAmount[] memory redemptions = computeRedemptionAmts(vaultNoteAmt, feePerc); - // burn notes - _burn(msg.sender, notes); + // burn vault notes + _burn(msg.sender, vaultNoteAmt); // transfer assets out uint8 redemptionsCount = uint8(redemptions.length); @@ -437,12 +592,6 @@ contract RolloverVault is return redemptions; } - /// @inheritdoc IVault - function recoverAndRedeem(uint256 notes) external override returns (TokenAmount[] memory) { - recover(); - return redeem(notes); - } - /// @inheritdoc IRolloverVault /// @dev Callers should call `recover` before executing `swapUnderlyingForPerps` to maximize vault liquidity. function swapUnderlyingForPerps(uint256 underlyingAmtIn) external nonReentrant whenNotPaused returns (uint256) { @@ -451,9 +600,7 @@ contract RolloverVault is IPerpetualTranche perp_ = perp; IERC20Upgradeable underlying_ = underlying; uint256 underlyingBalPre = underlying_.balanceOf(address(this)); - (uint256 perpAmtOut, uint256 perpFeeAmtToBurn, SubscriptionParams memory s) = computeUnderlyingToPerpSwapAmt( - underlyingAmtIn - ); + (uint256 perpAmtOut, , SubscriptionParams memory s) = computeUnderlyingToPerpSwapAmt(underlyingAmtIn); // Revert if insufficient tokens are swapped in or out if (perpAmtOut <= 0 || underlyingAmtIn <= 0) { @@ -464,12 +611,7 @@ contract RolloverVault is underlying_.safeTransferFrom(msg.sender, address(this), underlyingAmtIn); // tranche and mint perps as needed - _trancheAndMintPerps(perp_, underlying_, s.perpTVL, s.seniorTR, perpAmtOut + perpFeeAmtToBurn); - - // Pay perp's fee share by burning some of the minted perps - if (perpFeeAmtToBurn > 0) { - IERC20Burnable(address(perp_)).burn(perpFeeAmtToBurn); - } + _trancheAndMintPerps(perp_, underlying_, s.perpTVL, s.seniorTR, perpAmtOut); // transfer remaining perps out to the user IERC20Upgradeable(address(perp_)).safeTransfer(msg.sender, perpAmtOut); @@ -499,7 +641,7 @@ contract RolloverVault is IPerpetualTranche perp_ = perp; IERC20Upgradeable underlying_ = underlying; uint256 underlyingBalPre = underlying_.balanceOf(address(this)); - (uint256 underlyingAmtOut, uint256 perpFeeAmtToBurn, ) = computePerpToUnderlyingSwapAmt(perpAmtIn); + (uint256 underlyingAmtOut, , ) = computePerpToUnderlyingSwapAmt(perpAmtIn); // Revert if insufficient tokens are swapped in or out if (underlyingAmtOut <= 0 || perpAmtIn <= 0) { @@ -509,11 +651,6 @@ contract RolloverVault is // transfer perps in IERC20Upgradeable(perp_).safeTransferFrom(msg.sender, address(this), perpAmtIn); - // Pay perp's fee share by burning some of the transferred perps - if (perpFeeAmtToBurn > 0) { - IERC20Burnable(address(perp_)).burn(perpFeeAmtToBurn); - } - // Meld incoming perps _meldPerps(perp_); @@ -552,8 +689,7 @@ contract RolloverVault is //----------------------------------------------------------------------------- // When user swaps underlying for vault's perps -> perps are minted by the vault // We thus compute fees based on the post-mint subscription state. - uint256 perpFeePerc = feePolicy.computePerpMintFeePerc(); - uint256 vaultFeePerc = feePolicy.computeUnderlyingToPerpVaultSwapFeePerc( + uint256 feePerc = feePolicy.computeFeePerc( feePolicy.computeDeviationRatio(s), feePolicy.computeDeviationRatio( SubscriptionParams({ perpTVL: s.perpTVL + underlyingAmtIn, vaultTVL: s.vaultTVL, seniorTR: s.seniorTR }) @@ -561,13 +697,10 @@ contract RolloverVault is ); //----------------------------------------------------------------------------- - // Calculate perp fee share to be paid by the vault - uint256 perpFeeAmtToBurn = perpAmtOut.mulDiv(perpFeePerc, ONE, MathUpgradeable.Rounding.Up); - // We deduct fees by transferring out fewer perp tokens - perpAmtOut = perpAmtOut.mulDiv(ONE - (perpFeePerc + vaultFeePerc), ONE); + perpAmtOut = perpAmtOut.mulDiv(ONE - feePerc, ONE); - return (perpAmtOut, perpFeeAmtToBurn, s); + return (perpAmtOut, 0, s); } /// @inheritdoc IRolloverVault @@ -582,8 +715,7 @@ contract RolloverVault is //----------------------------------------------------------------------------- // When user swaps perps for vault's underlying -> perps are redeemed by the vault // We thus compute fees based on the post-burn subscription state. - uint256 perpFeePerc = feePolicy.computePerpBurnFeePerc(); - uint256 vaultFeePerc = feePolicy.computePerpToUnderlyingVaultSwapFeePerc( + uint256 feePerc = feePolicy.computeFeePerc( feePolicy.computeDeviationRatio(s), feePolicy.computeDeviationRatio( SubscriptionParams({ @@ -595,73 +727,73 @@ contract RolloverVault is ); //----------------------------------------------------------------------------- - // Calculate perp fee share to be paid by the vault - uint256 perpFeeAmtToBurn = perpAmtIn.mulDiv(perpFeePerc, ONE, MathUpgradeable.Rounding.Up); - // We deduct fees by transferring out fewer underlying tokens - underlyingAmtOut = underlyingAmtOut.mulDiv(ONE - (perpFeePerc + vaultFeePerc), ONE); + underlyingAmtOut = underlyingAmtOut.mulDiv(ONE - feePerc, ONE); - return (underlyingAmtOut, perpFeeAmtToBurn, s); + return (underlyingAmtOut, 0, s); } //-------------------------------------------------------------------------- // External & Public read methods - /// @inheritdoc IVault - function computeMintAmt(uint256 underlyingAmtIn) public view returns (uint256) { - //----------------------------------------------------------------------------- - uint256 feePerc = feePolicy.computeVaultMintFeePerc(); - //----------------------------------------------------------------------------- + /// @notice Computes the amount of vault notes minted when given amount of underlying asset tokens + /// are deposited into the system. + /// @param underlyingAmtIn The amount underlying tokens to be deposited into the vault. + /// @param feePerc The percentage of minted vault notes paid as fees. + /// @return vaultNoteAmtMint The amount of vault notes to be minted. + function computeMintAmt(uint256 underlyingAmtIn, uint256 feePerc) public view returns (uint256 vaultNoteAmtMint) { + uint256 vaultNoteSupply = totalSupply(); + //----------------------------------------------------------------------------- // Compute mint amt - uint256 noteSupply = totalSupply(); - uint256 notes = (noteSupply > 0) - ? noteSupply.mulDiv(underlyingAmtIn, getTVL()) + vaultNoteAmtMint = (vaultNoteSupply > 0) + ? vaultNoteSupply.mulDiv(underlyingAmtIn, getTVL()) : (underlyingAmtIn * INITIAL_RATE); // The mint fees are settled by simply minting fewer vault notes. - notes = notes.mulDiv(ONE - feePerc, ONE); - return notes; + vaultNoteAmtMint = vaultNoteAmtMint.mulDiv(ONE - feePerc, ONE); } - /// @inheritdoc IVault - function computeRedemptionAmts(uint256 noteAmtBurnt) public view returns (TokenAmount[] memory) { - uint256 noteSupply = totalSupply(); + /// @notice Computes the amount of asset tokens returned for redeeming vault notes. + /// @param vaultNoteAmtRedeemed The amount of vault notes to be redeemed. + /// @param feePerc The percentage of redeemed vault notes paid as fees. + /// @return returnedTokens The list of asset tokens and amounts returned. + function computeRedemptionAmts( + uint256 vaultNoteAmtRedeemed, + uint256 feePerc + ) public view returns (TokenAmount[] memory returnedTokens) { + uint256 vaultNoteSupply = totalSupply(); - //----------------------------------------------------------------------------- - uint256 feePerc = feePolicy.computeVaultBurnFeePerc(); //----------------------------------------------------------------------------- uint8 assetCount_ = 1 + uint8(_deployed.length()); // aggregating vault assets to be redeemed - TokenAmount[] memory redemptions = new TokenAmount[](assetCount_); + returnedTokens = new TokenAmount[](assetCount_); // underlying share to be redeemed IERC20Upgradeable underlying_ = underlying; - redemptions[0] = TokenAmount({ + returnedTokens[0] = TokenAmount({ token: underlying_, - amount: underlying_.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply) + amount: underlying_.balanceOf(address(this)).mulDiv(vaultNoteAmtRedeemed, vaultNoteSupply) }); - redemptions[0].amount = redemptions[0].amount.mulDiv(ONE - feePerc, ONE); + returnedTokens[0].amount = returnedTokens[0].amount.mulDiv(ONE - feePerc, ONE); for (uint8 i = 1; i < assetCount_; ++i) { // tranche token share to be redeemed IERC20Upgradeable token = IERC20Upgradeable(_deployed.at(i - 1)); - redemptions[i] = TokenAmount({ + returnedTokens[i] = TokenAmount({ token: token, - amount: token.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply) + amount: token.balanceOf(address(this)).mulDiv(vaultNoteAmtRedeemed, vaultNoteSupply) }); // deduct redemption fee - redemptions[i].amount = redemptions[i].amount.mulDiv(ONE - feePerc, ONE); + returnedTokens[i].amount = returnedTokens[i].amount.mulDiv(ONE - feePerc, ONE); // in case the redemption amount is just dust, we skip - if (redemptions[i].amount < TRANCHE_DUST_AMT) { - redemptions[i].amount = 0; + if (returnedTokens[i].amount < TRANCHE_DUST_AMT) { + returnedTokens[i].amount = 0; } } - - return redemptions; } /// @inheritdoc IVault @@ -676,7 +808,7 @@ contract RolloverVault is ITranche tranche = ITranche(_deployed.at(i)); uint256 balance = tranche.balanceOf(address(this)); if (balance > TRANCHE_DUST_AMT) { - totalValue += _computeVaultTrancheValue(tranche, underlying, balance); + totalValue += TrancheManager.computeTrancheValue(address(tranche), address(underlying), balance); } } @@ -695,7 +827,10 @@ contract RolloverVault is // Deployed asset else if (_deployed.contains(address(token))) { ITranche tranche = ITranche(address(token)); - return (balance > TRANCHE_DUST_AMT) ? _computeVaultTrancheValue(tranche, underlying, balance) : 0; + return + (balance > TRANCHE_DUST_AMT) + ? TrancheManager.computeTrancheValue(address(tranche), address(underlying), balance) + : 0; } // Not a vault asset, so returning zero @@ -730,6 +865,46 @@ contract RolloverVault is //-------------------------------------------------------------------------- // Private write methods + /// @dev Executes a system-level rebalance. This operation transfers value between + /// the perp reserve and the vault such that the system moves toward balance. + /// Performs some book-keeping to keep track of the vault and perp's assets. + function _rebalance(IPerpetualTranche perp_, IERC20Upgradeable underlying_) private { + // Claim mint/burn fees collected by perp. + perp_.claimFees(address(this)); + _meldPerps(perp_); + + SubscriptionParams memory s = _querySubscriptionState(perp_); + int256 underlyingAmtIntoPerp = feePolicy.computeRebalanceAmount(s); + + // When value is flowing into perp from the vault. + // We rebalance from perp to the vault. + if (underlyingAmtIntoPerp < 0) { + perp_.rebalanceToVault(underlyingAmtIntoPerp.abs()); + _meldPerps(perp_); // Meld residual perps, if any. + } + // When value is flowing from the vault to perp. + // We rebalance from the vault to perp. + else if (underlyingAmtIntoPerp > 0) { + // We transfer value by minting the perp tokens (after making required deposit) + // and then simply burning the newly minted perp tokens. + uint256 perpAmtToTransfer = (underlyingAmtIntoPerp.toUint256()).mulDiv(perp_.totalSupply(), s.perpTVL); + _trancheAndMintPerps(perp_, underlying_, s.perpTVL, s.seniorTR, perpAmtToTransfer); + IERC20Burnable(address(perp_)).burn(perpAmtToTransfer); + } + + // We pay the protocol fee on every rebalance. + uint256 protocolSharePerc = feePolicy.protocolSharePerc(); + if (protocolSharePerc > 0) { + address collector = feePolicy.protocolFeeCollector(); + perp.payProtocolFee(collector, protocolSharePerc); + _mint(collector, protocolSharePerc.mulDiv(totalSupply(), ONE - protocolSharePerc)); + } + + // Sync token balances. + _syncAsset(perp_); + _syncAsset(underlying_); + } + /// @dev Redeems tranche tokens held by the vault, for underlying. /// In the case of immature redemption, this method will recover other sibling tranches as well. /// Performs some book-keeping to keep track of the vault's assets. @@ -749,7 +924,7 @@ contract RolloverVault is // if bond has matured, redeem the tranche token if (bond.secondsToMaturity() <= 0) { // execute redemption - _execMatureTrancheRedemption(bond, tranche, trancheBalance); + TrancheManager.execMatureTrancheRedemption(bond, tranche, trancheBalance); // sync deployed asset _syncDeployedAsset(tranche); @@ -760,7 +935,7 @@ contract RolloverVault is else if (trancheBalance > TRANCHE_DUST_AMT) { // execute redemption BondTranches memory bt = bond.getTranches(); - _execImmatureTrancheRedemption(bond, bt); + TrancheManager.execImmatureTrancheRedemption(bond, bt); // sync deployed asset, i.e) current tranche and its sibling. _syncDeployedAsset(bt.tranches[0]); @@ -792,7 +967,7 @@ contract RolloverVault is } } - /// @dev Tranches the vault's underlying to mint perps.. + /// @dev Tranches the vault's underlying to mint perps. /// Performs some book-keeping to keep track of the vault's assets. function _trancheAndMintPerps( IPerpetualTranche perp_, @@ -818,29 +993,13 @@ contract RolloverVault is _tranche(depositBond, underlying_, underylingAmtToTranche); // Mint perps - _checkAndApproveMax(trancheIntoPerp, address(perp_), seniorAmtToDeposit); + IERC20Upgradeable(trancheIntoPerp).checkAndApproveMax(address(perp_), seniorAmtToDeposit); perp_.deposit(trancheIntoPerp, seniorAmtToDeposit); // sync holdings _syncDeployedAsset(trancheIntoPerp); } - /// @dev Given a bond and its tranche data, deposits the provided amount into the bond - /// and receives tranche tokens in return. - /// Performs some book-keeping to keep track of the vault's assets. - function _tranche(IBondController bond, IERC20Upgradeable underlying_, uint256 underlyingAmt) private { - // Get bond tranches - BondTranches memory bt = bond.getTranches(); - - // amount is tranched - _checkAndApproveMax(underlying_, address(bond), underlyingAmt); - bond.deposit(underlyingAmt); - - // sync holdings - _syncDeployedAsset(bt.tranches[0]); - _syncDeployedAsset(bt.tranches[1]); - } - /// @dev Rolls over freshly tranched tokens from the given bond for older tranches (close to maturity) from perp. /// Redeems intermediate tranches for underlying if possible. /// Performs some book-keeping to keep track of the vault's assets. @@ -860,7 +1019,7 @@ contract RolloverVault is uint256 trancheInAmtAvailable = trancheIntoPerp.balanceOf(address(this)); // Approve once for all rollovers - _checkAndApproveMax(trancheIntoPerp, address(perp_), trancheInAmtAvailable); + IERC20Upgradeable(trancheIntoPerp).checkAndApproveMax(address(perp_), trancheInAmtAvailable); // We pair the senior tranche token held by the vault (from the deposit bond) // with each of the perp's tokens available for rollovers and execute a rollover. @@ -899,37 +1058,21 @@ contract RolloverVault is return (rollover); } - /// @dev Low level method that redeems the given mature tranche for the underlying asset. - /// It interacts with the button-wood bond contract. - /// This function should NOT be called directly, use `recover()` or `_redeemTranche(tranche)` - /// which wrap this function with the internal book-keeping necessary, - /// to keep track of the vault's assets. - function _execMatureTrancheRedemption(IBondController bond, ITranche tranche, uint256 amount) private { - if (!bond.isMature()) { - bond.mature(); - } - bond.redeemMature(address(tranche), amount); - } - - /// @dev Low level method that redeems the given tranche for the underlying asset, before maturity. - /// If the vault holds sibling tranches with proportional balances, those will also get redeemed. - /// It interacts with the button-wood bond contract. - /// This function should NOT be called directly, use `recover()` or `recover(tranche)` - /// which wrap this function with the internal book-keeping necessary, - /// to keep track of the vault's assets. - function _execImmatureTrancheRedemption(IBondController bond, BondTranches memory bt) private { - uint256[] memory trancheAmts = bt.computeRedeemableTrancheAmounts(address(this)); + /// @dev Given a bond, deposits the provided amount into the bond + /// and receives tranche tokens in return. + /// Performs some book-keeping to keep track of the vault's assets. + function _tranche(IBondController bond, IERC20Upgradeable underlying_, uint256 underlyingAmt) private { + // Tranche + ITranche[2] memory t = bond.approveAndDeposit(underlying_, underlyingAmt); - // NOTE: It is guaranteed that if one tranche amount is zero, all amounts are zeros. - if (trancheAmts[0] > 0) { - bond.redeem(trancheAmts); - } + // sync holdings + _syncDeployedAsset(t[0]); + _syncDeployedAsset(t[1]); } /// @dev Syncs balance and updates the deployed list based on the vault's token balance. function _syncDeployedAsset(IERC20Upgradeable token) private { - uint256 balance = token.balanceOf(address(this)); - emit AssetSynced(token, balance); + uint256 balance = _syncAsset(token); bool inVault = _deployed.contains(address(token)); if (balance > 0 && !inVault) { @@ -945,16 +1088,9 @@ contract RolloverVault is } /// @dev Logs the token balance held by the vault. - function _syncAsset(IERC20Upgradeable token) private { - emit AssetSynced(token, token.balanceOf(address(this))); - } - - /// @dev Checks if the spender has sufficient allowance. If not, approves the maximum possible amount. - function _checkAndApproveMax(IERC20Upgradeable token, address spender, uint256 amount) private { - uint256 allowance = token.allowance(address(this), spender); - if (allowance < amount) { - token.safeApprove(spender, type(uint256).max); - } + function _syncAsset(IERC20Upgradeable token) private returns (uint256 balance) { + balance = token.balanceOf(address(this)); + emit AssetSynced(token, balance); } /// @dev Queries the current subscription state of the perp and vault systems. @@ -968,18 +1104,7 @@ contract RolloverVault is } //-------------------------------------------------------------------------- - // Private methods - - /// @dev Computes the value of the given amount of tranche tokens, based on it's current CDR. - /// Value is denominated in the underlying collateral. - function _computeVaultTrancheValue( - ITranche tranche, - IERC20Upgradeable collateralToken, - uint256 trancheAmt - ) private view returns (uint256) { - (uint256 trancheClaim, uint256 trancheSupply) = tranche.getTrancheCollateralization(collateralToken); - return trancheClaim.mulDiv(trancheAmt, trancheSupply, MathUpgradeable.Rounding.Up); - } + // Private view methods /// @dev Computes the balance of underlying tokens to NOT be used for any operation. function _totalReservedBalance(uint256 perpTVL, uint256 seniorTR) private view returns (uint256) { diff --git a/spot-contracts/contracts/RouterV2.sol b/spot-contracts/contracts/RouterV2.sol index a81ea85e..861f721c 100644 --- a/spot-contracts/contracts/RouterV2.sol +++ b/spot-contracts/contracts/RouterV2.sol @@ -11,6 +11,7 @@ import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import { BondTranches, BondTranchesHelpers } from "./_utils/BondTranchesHelpers.sol"; import { BondHelpers } from "./_utils/BondHelpers.sol"; +import { ERC20Helpers } from "./_utils/ERC20Helpers.sol"; /** * @title RouterV2 @@ -30,68 +31,61 @@ contract RouterV2 { using SafeERC20Upgradeable for IERC20Upgradeable; using SafeERC20Upgradeable for ITranche; using SafeERC20Upgradeable for IPerpetualTranche; + using ERC20Helpers for IERC20Upgradeable; /// @notice Calculates the amount of tranche tokens minted after depositing into the deposit bond. /// @dev Used by off-chain services to preview a tranche operation. /// @param perp Address of the perp contract. - /// @param collateralAmount The amount of collateral the user wants to tranche. + /// @param underlyingAmt The amount of underlying tokens the user wants to tranche. /// @return bond The address of the current deposit bond. /// @return trancheAmts The tranche tokens and amounts minted. function previewTranche( IPerpetualTranche perp, - uint256 collateralAmount + uint256 underlyingAmt ) external returns (IBondController, TokenAmount[] memory) { IBondController bond = perp.getDepositBond(); - return (bond, bond.previewDeposit(collateralAmount)); + return (bond, bond.previewDeposit(underlyingAmt)); } - /// @notice Tranches the collateral using the current deposit bond and then deposits individual tranches + /// @notice Tranches the underlying tokens using the current deposit bond and then deposits individual tranches /// to mint perp tokens. It transfers the perp tokens back to the /// transaction sender along with any unused tranches and fees. /// @param perp Address of the perp contract. /// @param bond Address of the deposit bond. - /// @param collateralAmount The amount of collateral the user wants to tranche. - function trancheAndDeposit(IPerpetualTranche perp, IBondController bond, uint256 collateralAmount) external { + /// @param underlyingAmt The amount of underlying tokens the user wants to tranche. + function trancheAndDeposit(IPerpetualTranche perp, IBondController bond, uint256 underlyingAmt) external { // If deposit bond does not exist, we first issue it. if (address(bond).code.length <= 0) { perp.updateState(); } BondTranches memory bt = bond.getTranches(); - IERC20Upgradeable collateralToken = IERC20Upgradeable(bond.collateralToken()); + IERC20Upgradeable underlying = IERC20Upgradeable(bond.collateralToken()); - // transfers collateral & fees to router - collateralToken.safeTransferFrom(msg.sender, address(this), collateralAmount); + // transfers underlying tokens & fees to router + underlying.safeTransferFrom(msg.sender, address(this), underlyingAmt); - // approves collateral to be tranched - _checkAndApproveMax(collateralToken, address(bond), collateralAmount); + // approves underlying tokens to be tranched + underlying.checkAndApproveMax(address(bond), underlyingAmt); - // tranches collateral - bond.deposit(collateralAmount); + // tranches underlying tokens + bond.deposit(underlyingAmt); // uses senior tranches to mint perps uint256 trancheAmt = bt.tranches[0].balanceOf(address(this)); - _checkAndApproveMax(bt.tranches[0], address(perp), trancheAmt); + IERC20Upgradeable(bt.tranches[0]).checkAndApproveMax(address(perp), trancheAmt); perp.deposit(bt.tranches[0], trancheAmt); // transfers remaining junior tranches back bt.tranches[1].safeTransfer(msg.sender, bt.tranches[1].balanceOf(address(this))); - // transfers any remaining collateral tokens back - uint256 collateralBalance = collateralToken.balanceOf(address(this)); - if (collateralBalance > 0) { - collateralToken.safeTransfer(msg.sender, collateralBalance); + // transfers any remaining underlying tokens back + uint256 underlyingBal = underlying.balanceOf(address(this)); + if (underlyingBal > 0) { + underlying.safeTransfer(msg.sender, underlyingBal); } // transfers perp tokens back perp.safeTransfer(msg.sender, perp.balanceOf(address(this))); } - - /// @dev Checks if the spender has sufficient allowance. If not, approves the maximum possible amount. - function _checkAndApproveMax(IERC20Upgradeable token, address spender, uint256 amount) private { - uint256 allowance = token.allowance(address(this), spender); - if (allowance < amount) { - token.safeApprove(spender, type(uint256).max); - } - } } diff --git a/spot-contracts/contracts/_interfaces/CommonTypes.sol b/spot-contracts/contracts/_interfaces/CommonTypes.sol index 52fbacf4..6ef1437d 100644 --- a/spot-contracts/contracts/_interfaces/CommonTypes.sol +++ b/spot-contracts/contracts/_interfaces/CommonTypes.sol @@ -26,3 +26,23 @@ struct RolloverData { /// @notice The amount of trancheIn tokens rolled in. uint256 trancheInAmt; } + +/// @notice A data structure to define a numeric Range. +struct Range { + // @dev Lower bound of the range. + uint256 lower; + // @dev Upper bound of the range. + uint256 upper; +} + +/// @notice A data structure to define a geometric Line with two points. +struct Line { + // @dev x-coordinate of the first point. + uint256 x1; + // @dev y-coordinate of the first point. + uint256 y1; + // @dev x-coordinate of the second point. + uint256 x2; + // @dev y-coordinate of the second point. + uint256 y2; +} diff --git a/spot-contracts/contracts/_interfaces/IFeePolicy.sol b/spot-contracts/contracts/_interfaces/IFeePolicy.sol index 5699611e..7c6cdc92 100644 --- a/spot-contracts/contracts/_interfaces/IFeePolicy.sol +++ b/spot-contracts/contracts/_interfaces/IFeePolicy.sol @@ -6,48 +6,33 @@ import { SubscriptionParams } from "./CommonTypes.sol"; interface IFeePolicy { /// @return The percentage of the mint perp tokens to be charged as fees, /// as a fixed-point number with {DECIMALS} decimal places. - function computePerpMintFeePerc() external view returns (uint256); + /// @dev Perp mint fees are paid to the vault. + function computeFeePerc(uint256 drPre, uint256 drPost) external view returns (uint256); - /// @return The percentage of the burnt perp tokens to be charged as fees, - /// as a fixed-point number with {DECIMALS} decimal places. - function computePerpBurnFeePerc() external view returns (uint256); + /// @return Number of decimals representing a multiplier of 1.0. So, 100% = 1*10**decimals. + function decimals() external view returns (uint8); - /// @param dr The current system deviation ratio. - /// @return The applied exchange rate adjustment between tranches into perp and - /// tokens out of perp during a rollover, - /// as a fixed-point number with {DECIMALS} decimal places. - /// @dev - A fee of 0%, implies the rollover exchange rate is unaltered. - /// example) 100 tranchesIn for 100 tranchesOut - /// - A fee of 1%, implies the exchange rate is adjusted in favor of tranchesIn. - /// example) 100 tranchesIn for 99 tranchesOut; i.e) perp enrichment - /// - A fee of -1%, implies the exchange rate is adjusted in favor of tranchesOut. - /// example) 99 tranchesIn for 100 tranchesOut - function computePerpRolloverFeePerc(uint256 dr) external view returns (int256); - - /// @return The percentage of the mint vault note amount to be charged as fees, - /// as a fixed-point number with {DECIMALS} decimal places. - function computeVaultMintFeePerc() external view returns (uint256); + /// @param s The subscription parameters of both the perp and vault systems. + /// @return The deviation ratio given the system subscription parameters. + function computeDeviationRatio(SubscriptionParams memory s) external view returns (uint256); - /// @return The percentage of the burnt vault note amount to be charged as fees, + /// @param seniorTR The senior tranche ratio of the deposit bond. + /// @return The "targetSR" adjusted senior tranche ratio, /// as a fixed-point number with {DECIMALS} decimal places. - function computeVaultBurnFeePerc() external view returns (uint256); + function computeDRNormSeniorTR(uint256 seniorTR) external view returns (uint256); - /// @param dr The current system deviation ratio. - /// @param dr_ The deviation ratio of the system after the operation is complete. - /// @return The percentage of perp tokens out to be charged as swap fees by the vault, - /// as a fixed-point numbers with {DECIMALS} decimal places. - function computeUnderlyingToPerpVaultSwapFeePerc(uint256 dr, uint256 dr_) external view returns (uint256); + /// @notice Computes magnitude and direction of value flow between perp and the rollover vault + /// expressed in underlying tokens. + /// @param s The subscription parameters of both the perp and vault systems. + /// @return underlyingAmtIntoPerp The value in underlying tokens, that need to flow from the vault into perp. + function computeRebalanceAmount(SubscriptionParams memory s) external view returns (int256 underlyingAmtIntoPerp); - /// @param dr The current system deviation ratio. - /// @param dr_ The deviation ratio of the system after the operation is complete. - /// @return The percentage of underlying tokens out to be charged as swap fees by the vault, - /// as a fixed-point numbers with {DECIMALS} decimal places. - function computePerpToUnderlyingVaultSwapFeePerc(uint256 dr, uint256 dr_) external view returns (uint256); + /// @return The share of the system tvl paid to the protocol owner as fees per rebalance. + function protocolSharePerc() external view returns (uint256); - /// @return Number of decimals representing a multiplier of 1.0. So, 100% = 1*10**decimals. - function decimals() external view returns (uint8); + /// @return Frequency of the periodic rebalance operation. + function rebalanceFreqSec() external view returns (uint256); - /// @param s The subscription parameters of both the perp and vault systems. - /// @return The deviation ratio given the system subscription parameters. - function computeDeviationRatio(SubscriptionParams memory s) external view returns (uint256); + /// @return The fee collector address. + function protocolFeeCollector() external view returns (address); } diff --git a/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol b/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol index 4b64fc01..82ccebc8 100644 --- a/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol +++ b/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol @@ -48,6 +48,19 @@ interface IPerpetualTranche is IERC20Upgradeable { uint256 trancheInAmt ) external returns (RolloverData memory r); + /// @notice Sends the collected mint/burn fees to the provided recipient address. + /// @param to The recipient address. + function claimFees(address to) external; + + /// @notice Pays the protocol fee collector a share of the TVL. + /// @param to The recipient address. + /// @param protocolSharePerc The share of tvl to be paid to the protocol as fees. + function payProtocolFee(address to, uint256 protocolSharePerc) external; + + /// @notice Debases the value of perp tokens, by transferring value to the vault. + /// @param underlyingAmtToTransfer The value in underlying tokens to be transferred to the vault. + function rebalanceToVault(uint256 underlyingAmtToTransfer) external; + /// @notice External contract that stores a predefined bond config and frequency, /// and issues new bonds when poked. /// @return The address of the bond issuer. @@ -57,8 +70,8 @@ interface IPerpetualTranche is IERC20Upgradeable { /// @return The address of the keeper. function keeper() external view returns (address); - /// @notice The address of the underlying rebasing ERC-20 collateral token backing the tranches. - /// @return Address of the underlying collateral token. + /// @notice The address of the underlying rebasing ERC-20 underlying token backing the tranches. + /// @return Address of the underlying token. function underlying() external view returns (IERC20Upgradeable); /// @return Address of perp's rollover vault. diff --git a/spot-contracts/contracts/_interfaces/IRolloverVault.sol b/spot-contracts/contracts/_interfaces/IRolloverVault.sol index 0b6c4742..791e311e 100644 --- a/spot-contracts/contracts/_interfaces/IRolloverVault.sol +++ b/spot-contracts/contracts/_interfaces/IRolloverVault.sol @@ -2,9 +2,30 @@ pragma solidity ^0.8.0; import { IVault } from "./IVault.sol"; -import { SubscriptionParams } from "./CommonTypes.sol"; +import { SubscriptionParams, TokenAmount } from "./CommonTypes.sol"; interface IRolloverVault is IVault { + /// @notice Gradually transfers value between the perp and vault, to bring the system back into balance. + /// @dev The rebalance function can be executed at-most once a day. + function rebalance() external; + + /// @notice Batch operation to mint both perp and rollover vault tokens. + /// @param underlyingAmtIn The amount of underlying tokens to be tranched. + /// @return perpAmt The amount of perp tokens minted. + /// @return vaultNoteAmt The amount of vault notes minted. + function mint2(uint256 underlyingAmtIn) external returns (uint256 perpAmt, uint256 vaultNoteAmt); + + /// @notice Batch operation to redeem both perp and rollover vault tokens for the underlying token and tranches. + /// @param perpAmtAvailable The amount of perp tokens available to redeem. + /// @param vaultNoteAmtAvailable The amount of vault notes available to redeem. + /// @return perpAmtBurnt The amount of perp tokens redeemed. + /// @return vaultNoteAmtBurnt The amount of vault notes redeemed. + /// @return returnedTokens The list of asset tokens and amounts returned. + function redeem2( + uint256 perpAmtAvailable, + uint256 vaultNoteAmtAvailable + ) external returns (uint256 perpAmtBurnt, uint256 vaultNoteAmtBurnt, TokenAmount[] memory returnedTokens); + /// @notice Allows users to swap their underlying tokens for perps held by the vault. /// @param underlyingAmtIn The amount of underlying tokens swapped in. /// @return The amount of perp tokens swapped out. diff --git a/spot-contracts/contracts/_interfaces/IVault.sol b/spot-contracts/contracts/_interfaces/IVault.sol index 28cd8258..5c7d8093 100644 --- a/spot-contracts/contracts/_interfaces/IVault.sol +++ b/spot-contracts/contracts/_interfaces/IVault.sol @@ -53,11 +53,6 @@ interface IVault is IERC20Upgradeable { /// @return The list of asset tokens and amounts redeemed. function redeem(uint256 notes) external returns (TokenAmount[] memory); - /// @notice Batches the recover and redeem functions. - /// @param notes The amount of notes to be burnt. - /// @return The list of asset tokens and amounts redeemed. - function recoverAndRedeem(uint256 notes) external returns (TokenAmount[] memory); - /// @return The total value of assets currently held by the vault, denominated in a standard unit of account. function getTVL() external view returns (uint256); @@ -82,15 +77,4 @@ interface IVault is IERC20Upgradeable { /// @param token The address of a token to check. /// @return If the given token is held by the vault. function isVaultAsset(IERC20Upgradeable token) external view returns (bool); - - /// @notice Computes the amount of notes minted when given amount of underlying asset tokens - /// are deposited into the system. - /// @param amount The amount tokens to be deposited into the vault. - /// @return The amount of notes to be minted. - function computeMintAmt(uint256 amount) external returns (uint256); - - /// @notice Computes the amount of asset tokens redeemed when burning given number of vault notes. - /// @param notes The amount of notes to be burnt. - /// @return The list of asset tokens and amounts redeemed. - function computeRedemptionAmts(uint256 notes) external returns (TokenAmount[] memory); } diff --git a/spot-contracts/contracts/_interfaces/ProtocolErrors.sol b/spot-contracts/contracts/_interfaces/ProtocolErrors.sol index 9015f188..e766f62b 100644 --- a/spot-contracts/contracts/_interfaces/ProtocolErrors.sol +++ b/spot-contracts/contracts/_interfaces/ProtocolErrors.sol @@ -34,6 +34,9 @@ error OutOfBounds(); /// @notice Expected the number of reserve assets to be under the limit. error ReserveCountOverLimit(); +/// @notice Expected range to be non-decreasing. +error InvalidRange(); + //------------------------------------------------------------------------- // Perp @@ -64,17 +67,14 @@ error DeployedCountOverLimit(); /// @notice Expected parent bond to have only 2 children tranches. error UnacceptableTrancheLength(); +/// @notice Not enough time has elapsed since last successful rebalance. +error LastRebalanceTooRecent(); + //------------------------------------------------------------------------- -// Fee Policy +// FeePolicy /// @notice Expected perc value to be at most (1 * 10**DECIMALS), i.e) 1.0 or 100%. error InvalidPerc(); -/// @notice Expected target subscription ratio to be within defined bounds. -error InvalidTargetSRBounds(); - -/// @notice Expected deviation ratio bounds to be valid. -error InvalidDRBounds(); - -/// @notice Expected sigmoid asymptotes to be within defined bounds. -error InvalidSigmoidAsymptotes(); +/// @notice Expected valid fee function definitions. +error InvalidFees(); diff --git a/spot-contracts/contracts/_test/LineHelpersTester.sol b/spot-contracts/contracts/_test/LineHelpersTester.sol new file mode 100644 index 00000000..9cb75c1c --- /dev/null +++ b/spot-contracts/contracts/_test/LineHelpersTester.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.20; + +import { LineHelpers } from "../_utils/LineHelpers.sol"; +import { Line, Range } from "../_interfaces/CommonTypes.sol"; + +contract LineHelpersTester { + function computePiecewiseAvgY( + Line memory fn1, + Line memory fn2, + Range memory xRange, + uint256 xBreakPt + ) public pure returns (int256) { + return LineHelpers.computePiecewiseAvgY(fn1, fn2, xRange, xBreakPt); + } + + function avgY(Line memory fn, uint256 xL, uint256 xU) public pure returns (int256) { + return LineHelpers.avgY(fn, xL, xU); + } +} diff --git a/spot-contracts/contracts/_test/mocks/DMock.sol b/spot-contracts/contracts/_test/mocks/DMock.sol new file mode 100644 index 00000000..ff0cac3b --- /dev/null +++ b/spot-contracts/contracts/_test/mocks/DMock.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract DMock { + struct MockCall { + bytes data; + bytes returnValue; + } + + // Maps a method signature to its mock call definition + mapping(bytes32 => MockCall) public mockCalls; + + // Fallback function to handle all calls + // solhint-disable-next-line + fallback(bytes calldata) external returns (bytes memory) { + // Check if mock has been defined based on {sig,param} pair + MockCall storage mockCall_ = mockCalls[keccak256(msg.data)]; + + // else check if generic mock has been defined based on sig + if (mockCall_.data.length <= 0) { + mockCall_ = mockCalls[keccak256(abi.encodePacked(bytes4(msg.data)))]; + } + + // solhint-disable-next-line custom-errors + require(mockCall_.data.length > 0, "DMock: method not mocked"); + + // Return the mocked return value + return mockCall_.returnValue; + } + + // Function to set up a mock call, given method sig and parameters + function mockCall(bytes memory data, bytes memory returnValue) public { + mockCalls[keccak256(data)] = MockCall(data, returnValue); + } + + // Function to set up a mock call, given just method sig + function mockMethod(bytes4 sig, bytes memory returnValue) public { + bytes memory data = abi.encodePacked(sig); + mockCalls[keccak256(data)] = MockCall(data, returnValue); + } + + // Function to clear mocked call + function clearMockCall(bytes memory data) public { + delete mockCalls[keccak256(data)]; + } + + // Function to clear mocked method call + function clearMockMethodSig(bytes4 sig) public { + bytes memory data = abi.encodePacked(sig); + delete mockCalls[keccak256(data)]; + } +} diff --git a/spot-contracts/contracts/_utils/BondHelpers.sol b/spot-contracts/contracts/_utils/BondHelpers.sol index b9aefc14..3903fef9 100644 --- a/spot-contracts/contracts/_utils/BondHelpers.sol +++ b/spot-contracts/contracts/_utils/BondHelpers.sol @@ -10,6 +10,7 @@ import { UnacceptableDeposit, UnacceptableTrancheLength } from "../_interfaces/P import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import { BondTranches } from "./BondTranchesHelpers.sol"; +import { ERC20Helpers } from "./ERC20Helpers.sol"; /** * @title BondHelpers @@ -20,6 +21,7 @@ import { BondTranches } from "./BondTranchesHelpers.sol"; library BondHelpers { using SafeCastUpgradeable for uint256; using MathUpgradeable for uint256; + using ERC20Helpers for IERC20Upgradeable; // Replicating value used here: // https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol @@ -97,4 +99,17 @@ library BondHelpers { return tranchesOut; } + + /// @notice Helper function which approves underlying tokens and mints tranche tokens by depositing into the provided bond contract. + /// @return The array of tranche tokens minted. + function approveAndDeposit( + IBondController b, + IERC20Upgradeable underlying_, + uint256 underlyingAmt + ) internal returns (ITranche[2] memory) { + BondTranches memory bt = getTranches(b); + underlying_.checkAndApproveMax(address(b), underlyingAmt); + b.deposit(underlyingAmt); + return bt.tranches; + } } diff --git a/spot-contracts/contracts/_utils/ERC20Helpers.sol b/spot-contracts/contracts/_utils/ERC20Helpers.sol new file mode 100644 index 00000000..d73becbc --- /dev/null +++ b/spot-contracts/contracts/_utils/ERC20Helpers.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.20; + +import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; + +/** + * @title ERC20Helpers + * + * @notice Library with helper functions for ERC20 Tokens. + * + */ +library ERC20Helpers { + using SafeERC20Upgradeable for IERC20Upgradeable; + + /// @notice Checks if the spender has sufficient allowance. If not, approves the maximum possible amount. + function checkAndApproveMax(IERC20Upgradeable token, address spender, uint256 amount) internal { + uint256 allowance = token.allowance(address(this), spender); + if (allowance < amount) { + token.safeApprove(spender, type(uint256).max); + } + } +} diff --git a/spot-contracts/contracts/_utils/LineHelpers.sol b/spot-contracts/contracts/_utils/LineHelpers.sol new file mode 100644 index 00000000..69b0e603 --- /dev/null +++ b/spot-contracts/contracts/_utils/LineHelpers.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.20; + +import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; +import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; +import { Line, Range } from "../_interfaces/CommonTypes.sol"; +import { InvalidRange } from "../_interfaces/ProtocolErrors.sol"; + +/** + * @title LineHelpers + * @notice Provides helper functions for working with linear functions and computing piecewise averages. + */ +library LineHelpers { + using MathUpgradeable for uint256; + using SafeCastUpgradeable for uint256; + using SafeCastUpgradeable for int256; + + /** + * @notice Computes the weighted average y-value over a specified x-range for a piecewise linear function. + * @dev This function considers two linear segments—`fn1` for x-values below the breakpoint (`xBreakPt`) + * and `fn2` for x-values above or equal to the breakpoint. If the entire x-range lies on one side of + * `xBreakPt`, it returns the average y-value computed over that range using the appropriate function. + * If the x-range spans `xBreakPt`, it computes a weighted average of the two sub-ranges, weighted by their lengths. + * @param fn1 The linear function used for x-values below `xBreakPt`. + * @param fn2 The linear function used for x-values above or equal to `xBreakPt`. + * @param xRange The x-range over which to compute the average. + * @param xBreakPt The x-coordinate where the piecewise function transitions from `fn1` to `fn2`. + * @return yVal The computed weighted average y-value over the x-range. + */ + function computePiecewiseAvgY( + Line memory fn1, + Line memory fn2, + Range memory xRange, + uint256 xBreakPt + ) internal pure returns (int256 yVal) { + if (xRange.lower > xRange.upper) { + revert InvalidRange(); + } + + if (xRange.upper <= xBreakPt) { + // Entire range is below the breakpoint. + yVal = avgY(fn1, xRange.lower, xRange.upper); + } else if (xRange.lower >= xBreakPt) { + // Entire range is above or equal to the breakpoint. + yVal = avgY(fn2, xRange.lower, xRange.upper); + } else { + // Range spans the breakpoint, so compute weighted average of both segments. + uint256 len1 = xBreakPt - xRange.lower; + uint256 len2 = xRange.upper - xBreakPt; + int256 avg1 = avgY(fn1, xRange.lower, xBreakPt); + int256 avg2 = avgY(fn2, xBreakPt, xRange.upper); + yVal = (avg1 * int256(len1) + avg2 * int256(len2)) / int256(xRange.upper - xRange.lower); + } + } + + /** + * @notice Computes the average y-value of a linear function over the interval [xL, xU]. + * @dev For a linear function defined as f(x) = m*x + c, the average value over [xL, xU] is: + * (f(xL) + f(xU)) / 2, which can be rewritten as m*((xL + xU)/2) + c. + * This function calculates the slope m using the two endpoints of the line and then computes + * the y-intercept c (using c = y2 - m*x2). If the line is horizontal (zero slope), it returns the + * constant y-value. Note that precision loss may occur due to integer division and type casting. + * Also, it is assumed that fn.x1 and fn.x2 are distinct to avoid division by zero. + * @param fn The linear function defined by two points (with properties x1, y1, x2, y2). + * @param xL The lower bound of the x-interval. + * @param xU The upper bound of the x-interval. + * @return The average y-value over the interval [xL, xU]. + */ + function avgY(Line memory fn, uint256 xL, uint256 xU) internal pure returns (int256) { + // If the line is horizontal, return the constant y-value. + if (fn.y1 == fn.y2) { + return fn.y2.toInt256(); + } + + // Calculate the slope (m = deltaY / deltaX). + int256 deltaY = fn.y2.toInt256() - fn.y1.toInt256(); + int256 deltaX = fn.x2.toInt256() - fn.x1.toInt256(); + + // Calculate the y-intercept using one of the endpoints: c = y2 - m * x2. + int256 c = fn.y2.toInt256() - ((fn.x2.toInt256() * deltaY) / deltaX); + + // Compute the average value over [xL, xU] as m*((xL + xU)/2) + c. + return ((((xL + xU).toInt256() * deltaY) / (2 * deltaX)) + c); + } +} diff --git a/spot-contracts/contracts/_utils/MathHelpers.sol b/spot-contracts/contracts/_utils/MathHelpers.sol new file mode 100644 index 00000000..c3c9ada3 --- /dev/null +++ b/spot-contracts/contracts/_utils/MathHelpers.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.20; + +import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; + +/** + * @title MathHelpers + * + * @notice Library with helper functions for math operations. + * + */ +library MathHelpers { + using MathUpgradeable for uint256; + + /// @dev Clips a given unsigned integer between provided min and max unsigned integer. + function clip(uint256 n, uint256 min, uint256 max) internal pure returns (uint256) { + return MathUpgradeable.min(MathUpgradeable.max(n, min), max); + } +} diff --git a/spot-contracts/contracts/_utils/TrancheManager.sol b/spot-contracts/contracts/_utils/TrancheManager.sol new file mode 100644 index 00000000..e4035999 --- /dev/null +++ b/spot-contracts/contracts/_utils/TrancheManager.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.20; + +import { IERC20Upgradeable, IBondController, ITranche } from "../_interfaces/IPerpetualTranche.sol"; + +import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; +import { BondTranches, BondTranchesHelpers } from "./BondTranchesHelpers.sol"; +import { TrancheHelpers } from "./TrancheHelpers.sol"; +import { BondHelpers } from "./BondHelpers.sol"; +import { ERC20Helpers } from "./ERC20Helpers.sol"; + +/** + * @title TrancheManager + * + * @notice Linked external library with helper functions for tranche management. + * + * @dev Proxies which use external libraries are by default NOT upgrade safe. + * We guarantee that this linked external library will never trigger selfdestruct, + * and this one is. + * + */ +library TrancheManager { + // data handling + using BondHelpers for IBondController; + using TrancheHelpers for ITranche; + using BondTranchesHelpers for BondTranches; + + // ERC20 operations + using SafeERC20Upgradeable for IERC20Upgradeable; + using ERC20Helpers for IERC20Upgradeable; + + // math + using MathUpgradeable for uint256; + + //-------------------------------------------------------------------------- + // Helper methods + + /// @notice Low level method that redeems the given mature tranche for the underlying asset. + /// It interacts with the button-wood bond contract. + function execMatureTrancheRedemption(IBondController bond, ITranche tranche, uint256 amount) external { + if (!bond.isMature()) { + bond.mature(); + } + bond.redeemMature(address(tranche), amount); + } + + /// @notice Low level method that redeems the given tranche for the underlying asset, before maturity. + /// If the contract holds sibling tranches with proportional balances, those will also get redeemed. + /// It interacts with the button-wood bond contract. + function execImmatureTrancheRedemption(IBondController bond, BondTranches memory bt) external { + uint256[] memory trancheAmts = bt.computeRedeemableTrancheAmounts(address(this)); + + // NOTE: It is guaranteed that if one tranche amount is zero, all amounts are zeros. + if (trancheAmts[0] > 0) { + bond.redeem(trancheAmts); + } + } + + /// @notice Computes the value of the given amount of tranche tokens, based on it's current CDR. + /// Value is denominated in the underlying collateral. + function computeTrancheValue( + address tranche, + address collateralToken, + uint256 trancheAmt + ) external view returns (uint256) { + (uint256 trancheClaim, uint256 trancheSupply) = ITranche(tranche).getTrancheCollateralization( + IERC20Upgradeable(collateralToken) + ); + return trancheClaim.mulDiv(trancheAmt, trancheSupply, MathUpgradeable.Rounding.Up); + } +} diff --git a/spot-contracts/external-artifacts/BondController.json b/spot-contracts/external-artifacts/BondController.json index 990e7666..7233f0ab 100644 --- a/spot-contracts/external-artifacts/BondController.json +++ b/spot-contracts/external-artifacts/BondController.json @@ -1,7 +1,7 @@ { "_format": "hh-sol-artifact-1", "contractName": "BondController", - "sourceName": "button-tranche/contracts/BondController.sol", + "sourceName": "contracts/BondController.sol", "abi": [ { "anonymous": false, @@ -41,19 +41,6 @@ "name": "FeeUpdate", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -130,6 +117,19 @@ "name": "RedeemMature", "type": "event" }, + { + "inputs": [], + "name": "collateralBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "collateralToken", @@ -246,6 +246,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "lastScaledCollateralBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "mature", @@ -413,8 +426,8 @@ "type": "function" } ], - "bytecode": "0x608060405234801561001057600080fd5b50612652806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806387b65207116100ad578063d59624b411610071578063d59624b41461025c578063ecf7085814610265578063f2fde38b1461026e578063f9afb26a14610281578063fc7b9c181461029457610121565b806387b65207146101fc5780638da5cb5b14610204578063ae4e7fdf14610229578063b2016bd414610236578063b6b55f251461024957610121565b80632a76ef31116100f45780632a76ef31146101b057806333d20e34146101c557806359eb8224146101d857806369fe0e2d146101e1578063715018a6146101f457610121565b806305b344101461012657806320e8e89e1461014257806324a9d8531461017557806326c259621461017e575b600080fd5b61012f60695481565b6040519081526020015b60405180910390f35b610165610150366004612082565b60686020526000908152604090205460ff1681565b6040519015158152602001610139565b61012f606e5481565b61019161018c36600461224d565b61029d565b604080516001600160a01b039093168352602083019190915201610139565b6101c36101be3660046120ba565b6102d5565b005b6101c36101d336600461213f565b610865565b61012f60675481565b6101c36101ef36600461224d565b6109f3565b6101c3610b0b565b6101c3610b41565b6033546001600160a01b03165b6040516001600160a01b039091168152602001610139565b606b546101659060ff1681565b606554610211906001600160a01b031681565b6101c361025736600461224d565b611073565b61012f606a5481565b61012f606d5481565b6101c361027c366004612082565b61161c565b6101c361028f36600461216a565b6116b7565b61012f606c5481565b606681815481106102ad57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b03909116915082565b60006102e16001611aff565b905080156102f9576000805461ff0019166101001790555b6001600160a01b03871661036b5760405162461bcd60e51b815260206004820152602e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368654660448201526d6163746f7279206164647265737360901b60648201526084015b60405180910390fd5b6001600160a01b0386166103d95760405162461bcd60e51b815260206004820152602f60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420636f6c6c6174657260448201526e616c546f6b656e206164647265737360881b6064820152608401610362565b6001600160a01b03851661043d5760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c69642061646d696e206164604482015264647265737360d81b6064820152608401610362565b601a8451111561049d5760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368652060448201526418dbdd5b9d60da1b6064820152608401610362565b6104a5611b85565b6104ae8561161c565b8351606755606580546001600160a01b0319166001600160a01b038816908117909155604080516395d89b4160e01b81529051600092916395d89b419160048083019286929190829003018186803b15801561050957600080fd5b505afa15801561051d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261054591908101906121bd565b90506000805b865181101561074757600087828151811061057657634e487b7160e01b600052603260045260246000fd5b602002602001015190506103e88111156105e05760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e63686520604482015264726174696f60d81b6064820152608401610362565b6105ea8184612522565b925060008b6001600160a01b031663ef55207c61060987868d51611bb4565b61061588878e51611bea565b8e6040518463ffffffff1660e01b8152600401610634939291906123e5565b602060405180830381600087803b15801561064e57600080fd5b505af1158015610662573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610686919061209e565b6040805180820182526001600160a01b0392831680825260208083019687526066805460018082018355600092835294517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94354600290920291820180546001600160a01b031916919098161790965596517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943559095019490945585526068909252909220805460ff1916909217909155508061073f816125c0565b91505061054b565b506103e881146107a85760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e63686520604482015265726174696f7360d01b6064820152608401610362565b4285116108055760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964206d61747572697479604482015264206461746560d81b6064820152608401610362565b505042606955606a839055606d829055801561085c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50505050505050565b606b5460ff166108c25760405162461bcd60e51b815260206004820152602260248201527f426f6e64436f6e74726f6c6c65723a20426f6e64206973206e6f74206d617475604482015261726560f01b6064820152608401610362565b6001600160a01b03821660009081526068602052604090205460ff1661093a5760405162461bcd60e51b815260206004820152602760248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e636865206044820152666164647265737360c81b6064820152608401610362565b604051630e6dfcd560e01b81526001600160a01b03831690630e6dfcd59061096a9033908190869060040161236b565b600060405180830381600087803b15801561098457600080fd5b505af1158015610998573d6000803e3d6000fd5b5050505080606c60008282546109ae9190612579565b909155507f5e9473a427344c9398fd27f132e093a6582e7177334cb912336f3c17af206edb90503383836040516109e79392919061236b565b60405180910390a15050565b6033546001600160a01b03163314610a1d5760405162461bcd60e51b815260040161036290612471565b606b5460ff1615610a7f5760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201526573657446656560d01b6064820152608401610362565b6032811115610ad05760405162461bcd60e51b815260206004820181905260248201527f426f6e64436f6e74726f6c6c65723a204e65772066656520746f6f20686967686044820152606401610362565b606e8190556040518181527f88258d7c1f0510045362f22cdeb36a2c501ef80d7a06168881189fb8480cfe2f9060200160405180910390a150565b6033546001600160a01b03163314610b355760405162461bcd60e51b815260040161036290612471565b610b3f6000611c08565b565b606b5460ff1615610b945760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d617475726500006044820152606401610362565b6033546001600160a01b0316331480610bae575042606a54105b610c095760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f206044820152656d617475726560d01b6064820152608401610362565b606b805460ff19166001179055606680546040805160208084028201810190925282815260009390929091849084015b82821015610c81576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610c39565b50506065546040516370a0823160e01b81523060048201529394506000936001600160a01b0390911692506370a08231915060240160206040518083038186803b158015610cce57600080fd5b505afa158015610ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d069190612265565b905060005b60018351610d199190612579565b81108015610d275750600082115b15610efc576000838281518110610d4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516000015190506000610dd8826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d9a57600080fd5b505afa158015610dae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd29190612265565b85611c5a565b9050610de48185612579565b606554909450610dfe906001600160a01b03168383611c72565b816001600160a01b0316630e6dfcd530610e206033546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a082319060240160206040518083038186803b158015610e5f57600080fd5b505afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190612265565b6040518463ffffffff1660e01b8152600401610eb59392919061236b565b600060405180830381600087803b158015610ecf57600080fd5b505af1158015610ee3573d6000803e3d6000fd5b5050505050508080610ef4906125c0565b915050610d0b565b5080156110435760008260018451610f149190612579565b81518110610f3257634e487b7160e01b600052603260045260246000fd5b602090810291909101015151606554909150610f58906001600160a01b03168284611c72565b806001600160a01b0316630e6dfcd530610f7a6033546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038616906370a082319060240160206040518083038186803b158015610fb957600080fd5b505afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190612265565b6040518463ffffffff1660e01b815260040161100f9392919061236b565b600060405180830381600087803b15801561102957600080fd5b505af115801561103d573d6000803e3d6000fd5b50505050505b6040513381527f2eb828fdc16ef5c267a7b18c3f8edf180aaff1a8921c4fe994fef55ddc8abe60906020016109e7565b600081116110c35760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420616d6f756e7400006044820152606401610362565b606c54801515806110d957506402540be4008210155b6111345760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420696e697469616c20604482015265185b5bdd5b9d60d21b6064820152608401610362565b606b5460ff16156111875760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d617475726500006044820152606401610362565b6065546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156111cb57600080fd5b505afa1580156111df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112039190612265565b9050606d54600014806112215750606d5461121e8483612522565b11155b61126d5760405162461bcd60e51b815260206004820152601d60248201527f426f6e64436f6e74726f6c6c65723a204465706f736974206c696d69740000006044820152606401610362565b60006066805480602002602001604051908101604052809291908181526020016000905b828210156112d9576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101611291565b50505050905060008060675467ffffffffffffffff81111561130b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611334578160200160208202803683370190505b50905060005b83518110156114035760006103e885838151811061136857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001518961137f919061255a565b611389919061253a565b905060008611801561139b5750600087115b156113b857856113ab888361255a565b6113b5919061253a565b90505b6113c28185612522565b9350808383815181106113e557634e487b7160e01b600052603260045260246000fd5b602090810291909101015250806113fb816125c0565b91505061133a565b5081606c60008282546114169190612522565b9091555050606554611433906001600160a01b0316333089611d8d565b606e5460005b82518110156115dd57600083828151811061146457634e487b7160e01b600052603260045260246000fd5b602002602001015190506000612710848361147f919061255a565b611489919061253a565b9050801561151f578683815181106114b157634e487b7160e01b600052603260045260246000fd5b6020908102919091010151516040516340c10f1960e01b8152306004820152602481018390526001600160a01b03909116906340c10f1990604401600060405180830381600087803b15801561150657600080fd5b505af115801561151a573d6000803e3d6000fd5b505050505b86838151811061153f57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b03166340c10f196115603390565b61156a8486612579565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156115b057600080fd5b505af11580156115c4573d6000803e3d6000fd5b50505050505080806115d5906125c0565b915050611439565b5060408051338152602081018990529081018290527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1590606001610853565b6033546001600160a01b031633146116465760405162461bcd60e51b815260040161036290612471565b6001600160a01b0381166116ab5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610362565b6116b481611c08565b50565b606b5460ff16156117195760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20426f6e6420697320616c7265616479206044820152656d617475726560d01b6064820152608401610362565b60006066805480602002602001604051908101604052809291908181526020016000905b82821015611785576000848152602090819020604080518082019091526002850290910180546001600160a01b0316825260019081015482840152908352909201910161173d565b50505050905080518251146117eb5760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642072656465656d20616044820152656d6f756e747360d01b6064820152608401610362565b6000805b835181101561183f5783818151811061181857634e487b7160e01b600052603260045260246000fd5b60200260200101518261182b9190612522565b915080611837816125c0565b9150506117ef565b5060005b83518110156119f55782818151811061186c57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151826103e886848151811061189c57634e487b7160e01b600052603260045260246000fd5b60200260200101516118ae919061255a565b6118b8919061253a565b146119165760405162461bcd60e51b815260206004820152602860248201527f426f6e64436f6e74726f6c6c65723a20496e76616c696420726564656d7074696044820152676f6e20726174696f60c01b6064820152608401610362565b82818151811061193657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316639dc29fac6119573390565b86848151811061197757634e487b7160e01b600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b81526004016119b09291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b1580156119ca57600080fd5b505af11580156119de573d6000803e3d6000fd5b5050505080806119ed906125c0565b915050611843565b506065546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015611a3a57600080fd5b505afa158015611a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a729190612265565b90506000606c548284611a85919061255a565b611a8f919061253a565b905082606c6000828254611aa39190612579565b9091555050606554611abf906001600160a01b03163383611c72565b7f95a8789c26436cc55b5951f117195be05dfa3022c619a84c1449f83f9cf870683386604051611af092919061238f565b60405180910390a15050505050565b60008054610100900460ff1615611b46578160ff166001148015611b225750303b155b611b3e5760405162461bcd60e51b815260040161036290612423565b506000611b80565b60005460ff808416911610611b6d5760405162461bcd60e51b815260040161036290612423565b506000805460ff191660ff831617905560015b919050565b600054610100900460ff16611bac5760405162461bcd60e51b8152600401610362906124a6565b610b3f611eb9565b606083611bc18484611ee9565b604051602001611bd29291906122c5565b60405160208183030381529060405290509392505050565b606083611bf78484611ee9565b604051602001611bd292919061231b565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818310611c695781611c6b565b825b9392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611cce91906122a9565b6000604051808303816000865af19150503d8060008114611d0b576040519150601f19603f3d011682016040523d82523d6000602084013e611d10565b606091505b5091509150818015611d3a575080511580611d3a575080806020019051810190611d3a919061219d565b611d865760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610362565b5050505050565b600080856001600160a01b03166323b872dd868686604051602401611db49392919061236b565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611ded91906122a9565b6000604051808303816000865af19150503d8060008114611e2a576040519150601f19603f3d011682016040523d82523d6000602084013e611e2f565b606091505b5091509150818015611e59575080511580611e59575080806020019051810190611e59919061219d565b611eb15760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610362565b505050505050565b600054610100900460ff16611ee05760405162461bcd60e51b8152600401610362906124a6565b610b3f33611c08565b604080518082018252601981527f4142434445464748494a4b4c4d4e4f505152535455565758590000000000000060208201528151600180825281840190935260609260009190602082018180368337019050509050611f4a600185612579565b851415611f9357602d60f91b81600081518110611f7757634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350611ff7565b818581518110611fb357634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b81600081518110611fdf57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053505b949350505050565b600082601f83011261200f578081fd5b8135602067ffffffffffffffff82111561202b5761202b6125f1565b8160051b61203a8282016124f1565b838152828101908684018388018501891015612054578687fd5b8693505b85841015612076578035835260019390930192918401918401612058565b50979650505050505050565b600060208284031215612093578081fd5b8135611c6b81612607565b6000602082840312156120af578081fd5b8151611c6b81612607565b60008060008060008060c087890312156120d2578182fd5b86356120dd81612607565b955060208701356120ed81612607565b945060408701356120fd81612607565b9350606087013567ffffffffffffffff811115612118578283fd5b61212489828a01611fff565b9350506080870135915060a087013590509295509295509295565b60008060408385031215612151578182fd5b823561215c81612607565b946020939093013593505050565b60006020828403121561217b578081fd5b813567ffffffffffffffff811115612191578182fd5b611ff784828501611fff565b6000602082840312156121ae578081fd5b81518015158114611c6b578182fd5b6000602082840312156121ce578081fd5b815167ffffffffffffffff808211156121e5578283fd5b818401915084601f8301126121f8578283fd5b81518181111561220a5761220a6125f1565b61221d601f8201601f19166020016124f1565b9150808252856020828501011115612233578384fd5b612244816020840160208601612590565b50949350505050565b60006020828403121561225e578081fd5b5035919050565b600060208284031215612276578081fd5b5051919050565b60008151808452612295816020860160208601612590565b601f01601f19169290920160200192915050565b600082516122bb818460208701612590565b9190910192915050565b60006d0213aba3a37b72a3930b731b432960951b825283516122ee81600e850160208801612590565b600160fd1b600e91840191820152835161230f81600f840160208801612590565b01600f01949350505050565b6000675452414e4348452d60c01b8252835161233e816008850160208801612590565b602d60f81b600891840191820152835161235f816009840160208801612590565b01600901949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b818110156123d8578451835293830193918301916001016123bc565b5090979650505050505050565b6000606082526123f8606083018661227d565b828103602084015261240a818661227d565b91505060018060a01b0383166040830152949350505050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b604051601f8201601f1916810167ffffffffffffffff8111828210171561251a5761251a6125f1565b604052919050565b60008219821115612535576125356125db565b500190565b60008261255557634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615612574576125746125db565b500290565b60008282101561258b5761258b6125db565b500390565b60005b838110156125ab578181015183820152602001612593565b838111156125ba576000848401525b50505050565b60006000198214156125d4576125d46125db565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146116b457600080fdfea26469706673582212204cabe8b296de4f5427a09b2b5306e8f086792d973fe69323cf400e4df44f87f764736f6c63430008030033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c806387b65207116100ad578063d59624b411610071578063d59624b41461025c578063ecf7085814610265578063f2fde38b1461026e578063f9afb26a14610281578063fc7b9c181461029457610121565b806387b65207146101fc5780638da5cb5b14610204578063ae4e7fdf14610229578063b2016bd414610236578063b6b55f251461024957610121565b80632a76ef31116100f45780632a76ef31146101b057806333d20e34146101c557806359eb8224146101d857806369fe0e2d146101e1578063715018a6146101f457610121565b806305b344101461012657806320e8e89e1461014257806324a9d8531461017557806326c259621461017e575b600080fd5b61012f60695481565b6040519081526020015b60405180910390f35b610165610150366004612082565b60686020526000908152604090205460ff1681565b6040519015158152602001610139565b61012f606e5481565b61019161018c36600461224d565b61029d565b604080516001600160a01b039093168352602083019190915201610139565b6101c36101be3660046120ba565b6102d5565b005b6101c36101d336600461213f565b610865565b61012f60675481565b6101c36101ef36600461224d565b6109f3565b6101c3610b0b565b6101c3610b41565b6033546001600160a01b03165b6040516001600160a01b039091168152602001610139565b606b546101659060ff1681565b606554610211906001600160a01b031681565b6101c361025736600461224d565b611073565b61012f606a5481565b61012f606d5481565b6101c361027c366004612082565b61161c565b6101c361028f36600461216a565b6116b7565b61012f606c5481565b606681815481106102ad57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b03909116915082565b60006102e16001611aff565b905080156102f9576000805461ff0019166101001790555b6001600160a01b03871661036b5760405162461bcd60e51b815260206004820152602e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368654660448201526d6163746f7279206164647265737360901b60648201526084015b60405180910390fd5b6001600160a01b0386166103d95760405162461bcd60e51b815260206004820152602f60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420636f6c6c6174657260448201526e616c546f6b656e206164647265737360881b6064820152608401610362565b6001600160a01b03851661043d5760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c69642061646d696e206164604482015264647265737360d81b6064820152608401610362565b601a8451111561049d5760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368652060448201526418dbdd5b9d60da1b6064820152608401610362565b6104a5611b85565b6104ae8561161c565b8351606755606580546001600160a01b0319166001600160a01b038816908117909155604080516395d89b4160e01b81529051600092916395d89b419160048083019286929190829003018186803b15801561050957600080fd5b505afa15801561051d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261054591908101906121bd565b90506000805b865181101561074757600087828151811061057657634e487b7160e01b600052603260045260246000fd5b602002602001015190506103e88111156105e05760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e63686520604482015264726174696f60d81b6064820152608401610362565b6105ea8184612522565b925060008b6001600160a01b031663ef55207c61060987868d51611bb4565b61061588878e51611bea565b8e6040518463ffffffff1660e01b8152600401610634939291906123e5565b602060405180830381600087803b15801561064e57600080fd5b505af1158015610662573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610686919061209e565b6040805180820182526001600160a01b0392831680825260208083019687526066805460018082018355600092835294517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94354600290920291820180546001600160a01b031916919098161790965596517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943559095019490945585526068909252909220805460ff1916909217909155508061073f816125c0565b91505061054b565b506103e881146107a85760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e63686520604482015265726174696f7360d01b6064820152608401610362565b4285116108055760405162461bcd60e51b815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964206d61747572697479604482015264206461746560d81b6064820152608401610362565b505042606955606a839055606d829055801561085c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50505050505050565b606b5460ff166108c25760405162461bcd60e51b815260206004820152602260248201527f426f6e64436f6e74726f6c6c65723a20426f6e64206973206e6f74206d617475604482015261726560f01b6064820152608401610362565b6001600160a01b03821660009081526068602052604090205460ff1661093a5760405162461bcd60e51b815260206004820152602760248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e636865206044820152666164647265737360c81b6064820152608401610362565b604051630e6dfcd560e01b81526001600160a01b03831690630e6dfcd59061096a9033908190869060040161236b565b600060405180830381600087803b15801561098457600080fd5b505af1158015610998573d6000803e3d6000fd5b5050505080606c60008282546109ae9190612579565b909155507f5e9473a427344c9398fd27f132e093a6582e7177334cb912336f3c17af206edb90503383836040516109e79392919061236b565b60405180910390a15050565b6033546001600160a01b03163314610a1d5760405162461bcd60e51b815260040161036290612471565b606b5460ff1615610a7f5760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201526573657446656560d01b6064820152608401610362565b6032811115610ad05760405162461bcd60e51b815260206004820181905260248201527f426f6e64436f6e74726f6c6c65723a204e65772066656520746f6f20686967686044820152606401610362565b606e8190556040518181527f88258d7c1f0510045362f22cdeb36a2c501ef80d7a06168881189fb8480cfe2f9060200160405180910390a150565b6033546001600160a01b03163314610b355760405162461bcd60e51b815260040161036290612471565b610b3f6000611c08565b565b606b5460ff1615610b945760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d617475726500006044820152606401610362565b6033546001600160a01b0316331480610bae575042606a54105b610c095760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f206044820152656d617475726560d01b6064820152608401610362565b606b805460ff19166001179055606680546040805160208084028201810190925282815260009390929091849084015b82821015610c81576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610c39565b50506065546040516370a0823160e01b81523060048201529394506000936001600160a01b0390911692506370a08231915060240160206040518083038186803b158015610cce57600080fd5b505afa158015610ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d069190612265565b905060005b60018351610d199190612579565b81108015610d275750600082115b15610efc576000838281518110610d4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516000015190506000610dd8826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d9a57600080fd5b505afa158015610dae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd29190612265565b85611c5a565b9050610de48185612579565b606554909450610dfe906001600160a01b03168383611c72565b816001600160a01b0316630e6dfcd530610e206033546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a082319060240160206040518083038186803b158015610e5f57600080fd5b505afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190612265565b6040518463ffffffff1660e01b8152600401610eb59392919061236b565b600060405180830381600087803b158015610ecf57600080fd5b505af1158015610ee3573d6000803e3d6000fd5b5050505050508080610ef4906125c0565b915050610d0b565b5080156110435760008260018451610f149190612579565b81518110610f3257634e487b7160e01b600052603260045260246000fd5b602090810291909101015151606554909150610f58906001600160a01b03168284611c72565b806001600160a01b0316630e6dfcd530610f7a6033546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038616906370a082319060240160206040518083038186803b158015610fb957600080fd5b505afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190612265565b6040518463ffffffff1660e01b815260040161100f9392919061236b565b600060405180830381600087803b15801561102957600080fd5b505af115801561103d573d6000803e3d6000fd5b50505050505b6040513381527f2eb828fdc16ef5c267a7b18c3f8edf180aaff1a8921c4fe994fef55ddc8abe60906020016109e7565b600081116110c35760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420616d6f756e7400006044820152606401610362565b606c54801515806110d957506402540be4008210155b6111345760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420696e697469616c20604482015265185b5bdd5b9d60d21b6064820152608401610362565b606b5460ff16156111875760405162461bcd60e51b815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d617475726500006044820152606401610362565b6065546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156111cb57600080fd5b505afa1580156111df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112039190612265565b9050606d54600014806112215750606d5461121e8483612522565b11155b61126d5760405162461bcd60e51b815260206004820152601d60248201527f426f6e64436f6e74726f6c6c65723a204465706f736974206c696d69740000006044820152606401610362565b60006066805480602002602001604051908101604052809291908181526020016000905b828210156112d9576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101611291565b50505050905060008060675467ffffffffffffffff81111561130b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611334578160200160208202803683370190505b50905060005b83518110156114035760006103e885838151811061136857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001518961137f919061255a565b611389919061253a565b905060008611801561139b5750600087115b156113b857856113ab888361255a565b6113b5919061253a565b90505b6113c28185612522565b9350808383815181106113e557634e487b7160e01b600052603260045260246000fd5b602090810291909101015250806113fb816125c0565b91505061133a565b5081606c60008282546114169190612522565b9091555050606554611433906001600160a01b0316333089611d8d565b606e5460005b82518110156115dd57600083828151811061146457634e487b7160e01b600052603260045260246000fd5b602002602001015190506000612710848361147f919061255a565b611489919061253a565b9050801561151f578683815181106114b157634e487b7160e01b600052603260045260246000fd5b6020908102919091010151516040516340c10f1960e01b8152306004820152602481018390526001600160a01b03909116906340c10f1990604401600060405180830381600087803b15801561150657600080fd5b505af115801561151a573d6000803e3d6000fd5b505050505b86838151811061153f57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b03166340c10f196115603390565b61156a8486612579565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156115b057600080fd5b505af11580156115c4573d6000803e3d6000fd5b50505050505080806115d5906125c0565b915050611439565b5060408051338152602081018990529081018290527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1590606001610853565b6033546001600160a01b031633146116465760405162461bcd60e51b815260040161036290612471565b6001600160a01b0381166116ab5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610362565b6116b481611c08565b50565b606b5460ff16156117195760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20426f6e6420697320616c7265616479206044820152656d617475726560d01b6064820152608401610362565b60006066805480602002602001604051908101604052809291908181526020016000905b82821015611785576000848152602090819020604080518082019091526002850290910180546001600160a01b0316825260019081015482840152908352909201910161173d565b50505050905080518251146117eb5760405162461bcd60e51b815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642072656465656d20616044820152656d6f756e747360d01b6064820152608401610362565b6000805b835181101561183f5783818151811061181857634e487b7160e01b600052603260045260246000fd5b60200260200101518261182b9190612522565b915080611837816125c0565b9150506117ef565b5060005b83518110156119f55782818151811061186c57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151826103e886848151811061189c57634e487b7160e01b600052603260045260246000fd5b60200260200101516118ae919061255a565b6118b8919061253a565b146119165760405162461bcd60e51b815260206004820152602860248201527f426f6e64436f6e74726f6c6c65723a20496e76616c696420726564656d7074696044820152676f6e20726174696f60c01b6064820152608401610362565b82818151811061193657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b0316639dc29fac6119573390565b86848151811061197757634e487b7160e01b600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b81526004016119b09291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b1580156119ca57600080fd5b505af11580156119de573d6000803e3d6000fd5b5050505080806119ed906125c0565b915050611843565b506065546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015611a3a57600080fd5b505afa158015611a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a729190612265565b90506000606c548284611a85919061255a565b611a8f919061253a565b905082606c6000828254611aa39190612579565b9091555050606554611abf906001600160a01b03163383611c72565b7f95a8789c26436cc55b5951f117195be05dfa3022c619a84c1449f83f9cf870683386604051611af092919061238f565b60405180910390a15050505050565b60008054610100900460ff1615611b46578160ff166001148015611b225750303b155b611b3e5760405162461bcd60e51b815260040161036290612423565b506000611b80565b60005460ff808416911610611b6d5760405162461bcd60e51b815260040161036290612423565b506000805460ff191660ff831617905560015b919050565b600054610100900460ff16611bac5760405162461bcd60e51b8152600401610362906124a6565b610b3f611eb9565b606083611bc18484611ee9565b604051602001611bd29291906122c5565b60405160208183030381529060405290509392505050565b606083611bf78484611ee9565b604051602001611bd292919061231b565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818310611c695781611c6b565b825b9392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611cce91906122a9565b6000604051808303816000865af19150503d8060008114611d0b576040519150601f19603f3d011682016040523d82523d6000602084013e611d10565b606091505b5091509150818015611d3a575080511580611d3a575080806020019051810190611d3a919061219d565b611d865760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610362565b5050505050565b600080856001600160a01b03166323b872dd868686604051602401611db49392919061236b565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611ded91906122a9565b6000604051808303816000865af19150503d8060008114611e2a576040519150601f19603f3d011682016040523d82523d6000602084013e611e2f565b606091505b5091509150818015611e59575080511580611e59575080806020019051810190611e59919061219d565b611eb15760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610362565b505050505050565b600054610100900460ff16611ee05760405162461bcd60e51b8152600401610362906124a6565b610b3f33611c08565b604080518082018252601981527f4142434445464748494a4b4c4d4e4f505152535455565758590000000000000060208201528151600180825281840190935260609260009190602082018180368337019050509050611f4a600185612579565b851415611f9357602d60f91b81600081518110611f7757634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350611ff7565b818581518110611fb357634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b81600081518110611fdf57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053505b949350505050565b600082601f83011261200f578081fd5b8135602067ffffffffffffffff82111561202b5761202b6125f1565b8160051b61203a8282016124f1565b838152828101908684018388018501891015612054578687fd5b8693505b85841015612076578035835260019390930192918401918401612058565b50979650505050505050565b600060208284031215612093578081fd5b8135611c6b81612607565b6000602082840312156120af578081fd5b8151611c6b81612607565b60008060008060008060c087890312156120d2578182fd5b86356120dd81612607565b955060208701356120ed81612607565b945060408701356120fd81612607565b9350606087013567ffffffffffffffff811115612118578283fd5b61212489828a01611fff565b9350506080870135915060a087013590509295509295509295565b60008060408385031215612151578182fd5b823561215c81612607565b946020939093013593505050565b60006020828403121561217b578081fd5b813567ffffffffffffffff811115612191578182fd5b611ff784828501611fff565b6000602082840312156121ae578081fd5b81518015158114611c6b578182fd5b6000602082840312156121ce578081fd5b815167ffffffffffffffff808211156121e5578283fd5b818401915084601f8301126121f8578283fd5b81518181111561220a5761220a6125f1565b61221d601f8201601f19166020016124f1565b9150808252856020828501011115612233578384fd5b612244816020840160208601612590565b50949350505050565b60006020828403121561225e578081fd5b5035919050565b600060208284031215612276578081fd5b5051919050565b60008151808452612295816020860160208601612590565b601f01601f19169290920160200192915050565b600082516122bb818460208701612590565b9190910192915050565b60006d0213aba3a37b72a3930b731b432960951b825283516122ee81600e850160208801612590565b600160fd1b600e91840191820152835161230f81600f840160208801612590565b01600f01949350505050565b6000675452414e4348452d60c01b8252835161233e816008850160208801612590565b602d60f81b600891840191820152835161235f816009840160208801612590565b01600901949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b818110156123d8578451835293830193918301916001016123bc565b5090979650505050505050565b6000606082526123f8606083018661227d565b828103602084015261240a818661227d565b91505060018060a01b0383166040830152949350505050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b604051601f8201601f1916810167ffffffffffffffff8111828210171561251a5761251a6125f1565b604052919050565b60008219821115612535576125356125db565b500190565b60008261255557634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615612574576125746125db565b500290565b60008282101561258b5761258b6125db565b500390565b60005b838110156125ab578181015183820152602001612593565b838111156125ba576000848401525b50505050565b60006000198214156125d4576125d46125db565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146116b457600080fdfea26469706673582212204cabe8b296de4f5427a09b2b5306e8f086792d973fe69323cf400e4df44f87f764736f6c63430008030033", + "bytecode": "0x608060405234801561001057600080fd5b50613e7e806100206000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80638da5cb5b116100d8578063c98c05b71161008c578063f2fde38b11610066578063f2fde38b14610309578063f9afb26a1461031c578063fc7b9c181461032f57610177565b8063c98c05b7146102ef578063d59624b4146102f7578063ecf708581461030057610177565b8063ae4e7fdf116100bd578063ae4e7fdf146102af578063b2016bd4146102bc578063b6b55f25146102dc57610177565b80638da5cb5b146102675780639f0205c7146102a657610177565b806333d20e341161012f57806369fe0e2d1161011457806369fe0e2d14610244578063715018a61461025757806387b652071461025f57610177565b806333d20e341461022857806359eb82241461023b57610177565b806324a9d8531161016057806324a9d853146101cb57806326c25962146101d45780632a76ef311461021357610177565b806305b344101461017c57806320e8e89e14610198575b600080fd5b61018560695481565b6040519081526020015b60405180910390f35b6101bb6101a6366004613864565b60686020526000908152604090205460ff1681565b604051901515815260200161018f565b610185606f5481565b6101e76101e2366004613a4d565b610338565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161018f565b61022661022136600461389c565b61037d565b005b610226610236366004613921565b610beb565b61018560675481565b610226610252366004613a4d565b610e4c565b610226611006565b610226611093565b60335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161018f565b610185606d5481565b606b546101bb9060ff1681565b6065546102819073ffffffffffffffffffffffffffffffffffffffff1681565b6102266102ea366004613a4d565b611a1d565b610185612327565b610185606a5481565b610185606e5481565b610226610317366004613864565b612499565b61022661032a36600461394c565b6125c9565b610185606c5481565b6066818154811061034857600080fd5b60009182526020909120600290910201805460019091015473ffffffffffffffffffffffffffffffffffffffff909116915082565b600054610100900460ff1680610396575060005460ff16155b610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600054610100900460ff1615801561046657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b73ffffffffffffffffffffffffffffffffffffffff8716610509576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368654660448201527f6163746f72792061646472657373000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff86166105ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420636f6c6c6174657260448201527f616c546f6b656e20616464726573730000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff851661064f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c69642061646d696e20616460448201527f6472657373000000000000000000000000000000000000000000000000000000606482015260840161041e565b601a845111156106e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368652060448201527f636f756e74000000000000000000000000000000000000000000000000000000606482015260840161041e565b6106e9612d6b565b6106f285612499565b8351606755606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8816908117909155604080517f95d89b410000000000000000000000000000000000000000000000000000000081529051600092916395d89b419160048083019286929190829003018186803b15801561078b57600080fd5b505afa15801561079f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107e5919081019061399f565b90506000805b8651811015610a8257600087828151811061082f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506103e88111156108cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f726174696f000000000000000000000000000000000000000000000000000000606482015260840161041e565b6108d58184613ce3565b925060008b73ffffffffffffffffffffffffffffffffffffffff1663ef55207c61090187868d51612e90565b61090d88878e51612ec7565b8e6040518463ffffffff1660e01b815260040161092c93929190613c48565b602060405180830381600087803b15801561094657600080fd5b505af115801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190613880565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff92831680825260208083019687526066805460018082018355600092835294517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94354600290920291820180547fffffffffffffffffffffffff000000000000000000000000000000000000000016919098161790965596517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94355909501949094558552606890925290922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555080610a7a81613db8565b9150506107eb565b506103e88114610b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f726174696f730000000000000000000000000000000000000000000000000000606482015260840161041e565b428511610ba3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964206d6174757269747960448201527f2064617465000000000000000000000000000000000000000000000000000000606482015260840161041e565b505042606955606a839055606e8290558015610be257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50505050505050565b606b5460ff16610c7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f426f6e64436f6e74726f6c6c65723a20426f6e64206973206e6f74206d61747560448201527f7265000000000000000000000000000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526068602052604090205460ff16610d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f6164647265737300000000000000000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff8216630e6dfcd533336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116602482015260448101849052606401600060405180830381600087803b158015610dc457600080fd5b505af1158015610dd8573d6000803e3d6000fd5b5050505080606c6000828254610dee9190613d71565b90915550506040805133815273ffffffffffffffffffffffffffffffffffffffff8416602082015280820183905290517f5e9473a427344c9398fd27f132e093a6582e7177334cb912336f3c17af206edb9181900360600190a15050565b60335473ffffffffffffffffffffffffffffffffffffffff163314610ecd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b606b5460ff1615610f60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201527f7365744665650000000000000000000000000000000000000000000000000000606482015260840161041e565b6032811115610fcb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f426f6e64436f6e74726f6c6c65723a204e65772066656520746f6f2068696768604482015260640161041e565b606f8190556040518181527f88258d7c1f0510045362f22cdeb36a2c501ef80d7a06168881189fb8480cfe2f9060200160405180910390a150565b60335473ffffffffffffffffffffffffffffffffffffffff163314611087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b6110916000612ee5565b565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b1580156110fd57600080fd5b505afa158015611111573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111359190613a65565b9050606d54811115611245576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156111ab57600080fd5b505afa1580156111bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e39190613a65565b905060006111f4606d548385612f5c565b6065549091506112429073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b61123d8486613d71565b613051565b50505b606b5460ff16156112b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d61747572650000604482015260640161041e565b60335473ffffffffffffffffffffffffffffffffffffffff163314806112d9575042606a54105b611365576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201527f6d61747572650000000000000000000000000000000000000000000000000000606482015260840161041e565b606b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055606680546040805160208084028201810190925282815260009390929091849084015b828210156114085760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff1682526001908101548284015290835290920191016113b3565b50506065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015293945060009373ffffffffffffffffffffffffffffffffffffffff90911692506370a08231915060240160206040518083038186803b15801561147b57600080fd5b505afa15801561148f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b39190613a65565b905060005b600183516114c69190613d71565b811080156114d45750600082115b15611758576000838281518110611514577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160000151905060006115ab8273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190613a65565b856131e7565b90506115b78185613d71565b6065549094506115de9073ffffffffffffffffffffffffffffffffffffffff168383613051565b8173ffffffffffffffffffffffffffffffffffffffff16630e6dfcd53061161a60335473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8716906370a082319060240160206040518083038186803b15801561167f57600080fd5b505afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190613a65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b15801561172b57600080fd5b505af115801561173f573d6000803e3d6000fd5b505050505050808061175090613db8565b9150506114b8565b50801561194157600082600184516117709190613d71565b815181106117a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102919091010151516065549091506117da9073ffffffffffffffffffffffffffffffffffffffff168284613051565b8073ffffffffffffffffffffffffffffffffffffffff16630e6dfcd53061181660335473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8616906370a082319060240160206040518083038186803b15801561187b57600080fd5b505afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190613a65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b15801561192757600080fd5b505af115801561193b573d6000803e3d6000fd5b50505050505b6040805133815290517f2eb828fdc16ef5c267a7b18c3f8edf180aaff1a8921c4fe994fef55ddc8abe609181900360200190a150506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690631da24f3e9060240160206040518083038186803b1580156119df57600080fd5b505afa1580156119f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a179190613a65565b606d5550565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613a65565b9050606d54811115611bc0576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611b3557600080fd5b505afa158015611b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6d9190613a65565b90506000611b7e606d548385612f5c565b606554909150611bbd9073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b50505b60008211611c2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420616d6f756e740000604482015260640161041e565b606b5460ff1615611c97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d61747572650000604482015260640161041e565b6065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611d0157600080fd5b505afa158015611d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d399190613a65565b9050606e5460001480611d575750606e54611d548483613ce3565b11155b611dbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f426f6e64436f6e74726f6c6c65723a204465706f736974206c696d6974000000604482015260640161041e565b60006066805480602002602001604051908101604052809291908181526020016000905b82821015611e365760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff168252600190810154828401529083529092019101611de1565b50505050905060008060675467ffffffffffffffff811115611e81577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015611eaa578160200160208202803683370190505b50905060005b8351811015611fa55760006103e8858381518110611ef7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516020015189611f0e9190613d34565b611f189190613cfb565b9050600086118015611f2c57506000606c54115b15611f4157611f3e81606c5488612f5c565b90505b611f4b8185613ce3565b935080838381518110611f87577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60209081029190910101525080611f9d81613db8565b915050611eb0565b5081606c6000828254611fb89190613ce3565b9091555050606554611fe29073ffffffffffffffffffffffffffffffffffffffff163330896131fd565b606f5460005b825181101561222f57600083828151811061202c577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600061271084836120479190613d34565b6120519190613cfb565b9050801561212657868381518110612092577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102919091010151516040517f40c10f190000000000000000000000000000000000000000000000000000000081523060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff909116906340c10f1990604401600060405180830381600087803b15801561210d57600080fd5b505af1158015612121573d6000803e3d6000fd5b505050505b86838151811061215f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff166340c10f1961218d3390565b6121978486613d71565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561220257600080fd5b505af1158015612216573d6000803e3d6000fd5b505050505050808061222790613db8565b915050611fe8565b50604080513381526020810189905280820183905290517f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360600190a161227861339c565b50506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169350631da24f3e925060240190505b60206040518083038186803b1580156122e857600080fd5b505afa1580156122fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123209190613a65565b606d555050565b6065546040517f1da24f3e000000000000000000000000000000000000000000000000000000008152306004820152600091829173ffffffffffffffffffffffffffffffffffffffff90911690631da24f3e9060240160206040518083038186803b15801561239557600080fd5b505afa1580156123a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cd9190613a65565b6065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b15801561243c57600080fd5b505afa158015612450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124749190613a65565b9050606d5482116124855780612492565b612492606d548284612f5c565b9250505090565b60335473ffffffffffffffffffffffffffffffffffffffff16331461251a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b73ffffffffffffffffffffffffffffffffffffffff81166125bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161041e565b6125c681612ee5565b50565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b15801561263357600080fd5b505afa158015612647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266b9190613a65565b9050606d5481111561276c576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156126e157600080fd5b505afa1580156126f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127199190613a65565b9050600061272a606d548385612f5c565b6065549091506127699073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b50505b606b5460ff16156127ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20426f6e6420697320616c72656164792060448201527f6d61747572650000000000000000000000000000000000000000000000000000606482015260840161041e565b60006066805480602002602001604051908101604052809291908181526020016000905b828210156128785760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff168252600190810154828401529083529092019101612823565b505050509050805183511461290f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642072656465656d206160448201527f6d6f756e74730000000000000000000000000000000000000000000000000000606482015260840161041e565b6000805b845181101561297c57848181518110612955577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151826129689190613ce3565b91508061297481613db8565b915050612913565b5060005b8451811015612bdf578281815181106129c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160200151826103e8878481518110612a0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612a1d9190613d34565b612a279190613cfb565b14612ab4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f426f6e64436f6e74726f6c6c65723a20496e76616c696420726564656d70746960448201527f6f6e20726174696f000000000000000000000000000000000000000000000000606482015260840161041e565b828181518110612aed577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16639dc29fac612b1b3390565b878481518110612b54577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b8152600401612b9a92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b600060405180830381600087803b158015612bb457600080fd5b505af1158015612bc8573d6000803e3d6000fd5b505050508080612bd790613db8565b915050612980565b506065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015612c4a57600080fd5b505afa158015612c5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c829190613a65565b90506000612c938383606c54612f5c565b905082606c6000828254612ca79190613d71565b9091555050606554612cd09073ffffffffffffffffffffffffffffffffffffffff163383613051565b7f95a8789c26436cc55b5951f117195be05dfa3022c619a84c1449f83f9cf870683387604051612d01929190613be5565b60405180910390a1612d1161339c565b50506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169250631da24f3e91506024016122d0565b600054610100900460ff1680612d84575060005460ff16155b612e10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff16158015612e4f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b612e57613433565b612e5f613547565b80156125c657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b606083612e9d8484613634565b604051602001612eae929190613ae3565b60405160208183030381529060405290505b9392505050565b606083612ed48484613634565b604051602001612eae929190613b64565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060001415612fdc57838281612fd2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b0492505050612ec0565b808411612fe857600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916130e89190613ac7565b6000604051808303816000865af19150503d8060008114613125576040519150601f19603f3d011682016040523d82523d6000602084013e61312a565b606091505b5091509150818015613154575080511580613154575080806020019051810190613154919061397f565b6131e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c656400000000000000000000000000000000000000606482015260840161041e565b5050505050565b60008183106131f65781612ec0565b5090919050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161329c9190613ac7565b6000604051808303816000865af19150503d80600081146132d9576040519150601f19603f3d011682016040523d82523d6000602084013e6132de565b606091505b5091509150818015613308575080511580613308575080806020019051810190613308919061397f565b613394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c6564000000000000000000000000000000606482015260840161041e565b505050505050565b6402540be400606c541015611091576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f426f6e64436f6e74726f6c6c65723a204578706563746564206d696e696d756d60448201527f2076616c69642064656274000000000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff168061344c575060005460ff16155b6134d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff16158015612e5f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661010117905580156125c657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b600054610100900460ff1680613560575060005460ff16155b6135ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff1615801561362b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b612e5f33612ee5565b604080518082018252601981527f4142434445464748494a4b4c4d4e4f505152535455565758590000000000000060208201528151600180825281840190935260609260009190602082018180368337019050509050613695600185613d71565b85141561372b577f5a00000000000000000000000000000000000000000000000000000000000000816000815181106136f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506137d9565b818581518110613764577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602001015160f81c60f81b816000815181106137a9577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b949350505050565b600082601f8301126137f1578081fd5b8135602067ffffffffffffffff82111561380d5761380d613e20565b8160051b61381c828201613c94565b838152828101908684018388018501891015613836578687fd5b8693505b8584101561385857803583526001939093019291840191840161383a565b50979650505050505050565b600060208284031215613875578081fd5b8135612ec081613e4f565b600060208284031215613891578081fd5b8151612ec081613e4f565b60008060008060008060c087890312156138b4578182fd5b86356138bf81613e4f565b955060208701356138cf81613e4f565b945060408701356138df81613e4f565b9350606087013567ffffffffffffffff8111156138fa578283fd5b61390689828a016137e1565b9350506080870135915060a087013590509295509295509295565b60008060408385031215613933578182fd5b823561393e81613e4f565b946020939093013593505050565b60006020828403121561395d578081fd5b813567ffffffffffffffff811115613973578182fd5b6137d9848285016137e1565b600060208284031215613990578081fd5b81518015158114612ec0578182fd5b6000602082840312156139b0578081fd5b815167ffffffffffffffff808211156139c7578283fd5b818401915084601f8301126139da578283fd5b8151818111156139ec576139ec613e20565b613a1d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613c94565b9150808252856020828501011115613a33578384fd5b613a44816020840160208601613d88565b50949350505050565b600060208284031215613a5e578081fd5b5035919050565b600060208284031215613a76578081fd5b5051919050565b60008151808452613a95816020860160208601613d88565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008251613ad9818460208701613d88565b9190910192915050565b60007f427574746f6e5472616e6368652000000000000000000000000000000000000082528351613b1b81600e850160208801613d88565b7f2000000000000000000000000000000000000000000000000000000000000000600e918401918201528351613b5881600f840160208801613d88565b01600f01949350505050565b60007f5452414e4348452d00000000000000000000000000000000000000000000000082528351613b9c816008850160208801613d88565b7f2d000000000000000000000000000000000000000000000000000000000000006008918401918201528351613bd9816009840160208801613d88565b01600901949350505050565b60006040820173ffffffffffffffffffffffffffffffffffffffff8516835260206040818501528185518084526060860191508287019350845b81811015613c3b57845183529383019391830191600101613c1f565b5090979650505050505050565b600060608252613c5b6060830186613a7d565b8281036020840152613c6d8186613a7d565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613cdb57613cdb613e20565b604052919050565b60008219821115613cf657613cf6613df1565b500190565b600082613d2f577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613d6c57613d6c613df1565b500290565b600082821015613d8357613d83613df1565b500390565b60005b83811015613da3578181015183820152602001613d8b565b83811115613db2576000848401525b50505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613dea57613dea613df1565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146125c657600080fdfea164736f6c6343000803000a", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101775760003560e01c80638da5cb5b116100d8578063c98c05b71161008c578063f2fde38b11610066578063f2fde38b14610309578063f9afb26a1461031c578063fc7b9c181461032f57610177565b8063c98c05b7146102ef578063d59624b4146102f7578063ecf708581461030057610177565b8063ae4e7fdf116100bd578063ae4e7fdf146102af578063b2016bd4146102bc578063b6b55f25146102dc57610177565b80638da5cb5b146102675780639f0205c7146102a657610177565b806333d20e341161012f57806369fe0e2d1161011457806369fe0e2d14610244578063715018a61461025757806387b652071461025f57610177565b806333d20e341461022857806359eb82241461023b57610177565b806324a9d8531161016057806324a9d853146101cb57806326c25962146101d45780632a76ef311461021357610177565b806305b344101461017c57806320e8e89e14610198575b600080fd5b61018560695481565b6040519081526020015b60405180910390f35b6101bb6101a6366004613864565b60686020526000908152604090205460ff1681565b604051901515815260200161018f565b610185606f5481565b6101e76101e2366004613a4d565b610338565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161018f565b61022661022136600461389c565b61037d565b005b610226610236366004613921565b610beb565b61018560675481565b610226610252366004613a4d565b610e4c565b610226611006565b610226611093565b60335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161018f565b610185606d5481565b606b546101bb9060ff1681565b6065546102819073ffffffffffffffffffffffffffffffffffffffff1681565b6102266102ea366004613a4d565b611a1d565b610185612327565b610185606a5481565b610185606e5481565b610226610317366004613864565b612499565b61022661032a36600461394c565b6125c9565b610185606c5481565b6066818154811061034857600080fd5b60009182526020909120600290910201805460019091015473ffffffffffffffffffffffffffffffffffffffff909116915082565b600054610100900460ff1680610396575060005460ff16155b610427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600054610100900460ff1615801561046657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b73ffffffffffffffffffffffffffffffffffffffff8716610509576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368654660448201527f6163746f72792061646472657373000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff86166105ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420636f6c6c6174657260448201527f616c546f6b656e20616464726573730000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff851661064f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c69642061646d696e20616460448201527f6472657373000000000000000000000000000000000000000000000000000000606482015260840161041e565b601a845111156106e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20696e76616c6964207472616e6368652060448201527f636f756e74000000000000000000000000000000000000000000000000000000606482015260840161041e565b6106e9612d6b565b6106f285612499565b8351606755606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8816908117909155604080517f95d89b410000000000000000000000000000000000000000000000000000000081529051600092916395d89b419160048083019286929190829003018186803b15801561078b57600080fd5b505afa15801561079f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107e5919081019061399f565b90506000805b8651811015610a8257600087828151811061082f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506103e88111156108cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f726174696f000000000000000000000000000000000000000000000000000000606482015260840161041e565b6108d58184613ce3565b925060008b73ffffffffffffffffffffffffffffffffffffffff1663ef55207c61090187868d51612e90565b61090d88878e51612ec7565b8e6040518463ffffffff1660e01b815260040161092c93929190613c48565b602060405180830381600087803b15801561094657600080fd5b505af115801561095a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097e9190613880565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff92831680825260208083019687526066805460018082018355600092835294517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94354600290920291820180547fffffffffffffffffffffffff000000000000000000000000000000000000000016919098161790965596517f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e94355909501949094558552606890925290922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555080610a7a81613db8565b9150506107eb565b506103e88114610b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f726174696f730000000000000000000000000000000000000000000000000000606482015260840161041e565b428511610ba3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964206d6174757269747960448201527f2064617465000000000000000000000000000000000000000000000000000000606482015260840161041e565b505042606955606a839055606e8290558015610be257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50505050505050565b606b5460ff16610c7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f426f6e64436f6e74726f6c6c65723a20426f6e64206973206e6f74206d61747560448201527f7265000000000000000000000000000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526068602052604090205460ff16610d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f426f6e64436f6e74726f6c6c65723a20496e76616c6964207472616e6368652060448201527f6164647265737300000000000000000000000000000000000000000000000000606482015260840161041e565b73ffffffffffffffffffffffffffffffffffffffff8216630e6dfcd533336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116602482015260448101849052606401600060405180830381600087803b158015610dc457600080fd5b505af1158015610dd8573d6000803e3d6000fd5b5050505080606c6000828254610dee9190613d71565b90915550506040805133815273ffffffffffffffffffffffffffffffffffffffff8416602082015280820183905290517f5e9473a427344c9398fd27f132e093a6582e7177334cb912336f3c17af206edb9181900360600190a15050565b60335473ffffffffffffffffffffffffffffffffffffffff163314610ecd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b606b5460ff1615610f60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201527f7365744665650000000000000000000000000000000000000000000000000000606482015260840161041e565b6032811115610fcb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f426f6e64436f6e74726f6c6c65723a204e65772066656520746f6f2068696768604482015260640161041e565b606f8190556040518181527f88258d7c1f0510045362f22cdeb36a2c501ef80d7a06168881189fb8480cfe2f9060200160405180910390a150565b60335473ffffffffffffffffffffffffffffffffffffffff163314611087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b6110916000612ee5565b565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b1580156110fd57600080fd5b505afa158015611111573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111359190613a65565b9050606d54811115611245576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156111ab57600080fd5b505afa1580156111bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e39190613a65565b905060006111f4606d548385612f5c565b6065549091506112429073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b61123d8486613d71565b613051565b50505b606b5460ff16156112b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d61747572650000604482015260640161041e565b60335473ffffffffffffffffffffffffffffffffffffffff163314806112d9575042606a54105b611365576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642063616c6c20746f2060448201527f6d61747572650000000000000000000000000000000000000000000000000000606482015260840161041e565b606b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055606680546040805160208084028201810190925282815260009390929091849084015b828210156114085760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff1682526001908101548284015290835290920191016113b3565b50506065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015293945060009373ffffffffffffffffffffffffffffffffffffffff90911692506370a08231915060240160206040518083038186803b15801561147b57600080fd5b505afa15801561148f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b39190613a65565b905060005b600183516114c69190613d71565b811080156114d45750600082115b15611758576000838281518110611514577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160000151905060006115ab8273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a59190613a65565b856131e7565b90506115b78185613d71565b6065549094506115de9073ffffffffffffffffffffffffffffffffffffffff168383613051565b8173ffffffffffffffffffffffffffffffffffffffff16630e6dfcd53061161a60335473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8716906370a082319060240160206040518083038186803b15801561167f57600080fd5b505afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190613a65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b15801561172b57600080fd5b505af115801561173f573d6000803e3d6000fd5b505050505050808061175090613db8565b9150506114b8565b50801561194157600082600184516117709190613d71565b815181106117a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102919091010151516065549091506117da9073ffffffffffffffffffffffffffffffffffffffff168284613051565b8073ffffffffffffffffffffffffffffffffffffffff16630e6dfcd53061181660335473ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8616906370a082319060240160206040518083038186803b15801561187b57600080fd5b505afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190613a65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b15801561192757600080fd5b505af115801561193b573d6000803e3d6000fd5b50505050505b6040805133815290517f2eb828fdc16ef5c267a7b18c3f8edf180aaff1a8921c4fe994fef55ddc8abe609181900360200190a150506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690631da24f3e9060240160206040518083038186803b1580156119df57600080fd5b505afa1580156119f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a179190613a65565b606d5550565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613a65565b9050606d54811115611bc0576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611b3557600080fd5b505afa158015611b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6d9190613a65565b90506000611b7e606d548385612f5c565b606554909150611bbd9073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b50505b60008211611c2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20696e76616c696420616d6f756e740000604482015260640161041e565b606b5460ff1615611c97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6e64436f6e74726f6c6c65723a20416c7265616479206d61747572650000604482015260640161041e565b6065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611d0157600080fd5b505afa158015611d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d399190613a65565b9050606e5460001480611d575750606e54611d548483613ce3565b11155b611dbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f426f6e64436f6e74726f6c6c65723a204465706f736974206c696d6974000000604482015260640161041e565b60006066805480602002602001604051908101604052809291908181526020016000905b82821015611e365760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff168252600190810154828401529083529092019101611de1565b50505050905060008060675467ffffffffffffffff811115611e81577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015611eaa578160200160208202803683370190505b50905060005b8351811015611fa55760006103e8858381518110611ef7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516020015189611f0e9190613d34565b611f189190613cfb565b9050600086118015611f2c57506000606c54115b15611f4157611f3e81606c5488612f5c565b90505b611f4b8185613ce3565b935080838381518110611f87577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60209081029190910101525080611f9d81613db8565b915050611eb0565b5081606c6000828254611fb89190613ce3565b9091555050606554611fe29073ffffffffffffffffffffffffffffffffffffffff163330896131fd565b606f5460005b825181101561222f57600083828151811061202c577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600061271084836120479190613d34565b6120519190613cfb565b9050801561212657868381518110612092577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020908102919091010151516040517f40c10f190000000000000000000000000000000000000000000000000000000081523060048201526024810183905273ffffffffffffffffffffffffffffffffffffffff909116906340c10f1990604401600060405180830381600087803b15801561210d57600080fd5b505af1158015612121573d6000803e3d6000fd5b505050505b86838151811061215f577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff166340c10f1961218d3390565b6121978486613d71565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561220257600080fd5b505af1158015612216573d6000803e3d6000fd5b505050505050808061222790613db8565b915050611fe8565b50604080513381526020810189905280820183905290517f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360600190a161227861339c565b50506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169350631da24f3e925060240190505b60206040518083038186803b1580156122e857600080fd5b505afa1580156122fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123209190613a65565b606d555050565b6065546040517f1da24f3e000000000000000000000000000000000000000000000000000000008152306004820152600091829173ffffffffffffffffffffffffffffffffffffffff90911690631da24f3e9060240160206040518083038186803b15801561239557600080fd5b505afa1580156123a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cd9190613a65565b6065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b15801561243c57600080fd5b505afa158015612450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124749190613a65565b9050606d5482116124855780612492565b612492606d548284612f5c565b9250505090565b60335473ffffffffffffffffffffffffffffffffffffffff16331461251a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161041e565b73ffffffffffffffffffffffffffffffffffffffff81166125bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161041e565b6125c681612ee5565b50565b6065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff1690631da24f3e9060240160206040518083038186803b15801561263357600080fd5b505afa158015612647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266b9190613a65565b9050606d5481111561276c576065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156126e157600080fd5b505afa1580156126f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127199190613a65565b9050600061272a606d548385612f5c565b6065549091506127699073ffffffffffffffffffffffffffffffffffffffff1661123360335473ffffffffffffffffffffffffffffffffffffffff1690565b50505b606b5460ff16156127ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20426f6e6420697320616c72656164792060448201527f6d61747572650000000000000000000000000000000000000000000000000000606482015260840161041e565b60006066805480602002602001604051908101604052809291908181526020016000905b828210156128785760008481526020908190206040805180820190915260028502909101805473ffffffffffffffffffffffffffffffffffffffff168252600190810154828401529083529092019101612823565b505050509050805183511461290f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f426f6e64436f6e74726f6c6c65723a20496e76616c69642072656465656d206160448201527f6d6f756e74730000000000000000000000000000000000000000000000000000606482015260840161041e565b6000805b845181101561297c57848181518110612955577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151826129689190613ce3565b91508061297481613db8565b915050612913565b5060005b8451811015612bdf578281815181106129c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160200151826103e8878481518110612a0b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612a1d9190613d34565b612a279190613cfb565b14612ab4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f426f6e64436f6e74726f6c6c65723a20496e76616c696420726564656d70746960448201527f6f6e20726174696f000000000000000000000000000000000000000000000000606482015260840161041e565b828181518110612aed577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16639dc29fac612b1b3390565b878481518110612b54577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516040518363ffffffff1660e01b8152600401612b9a92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b600060405180830381600087803b158015612bb457600080fd5b505af1158015612bc8573d6000803e3d6000fd5b505050508080612bd790613db8565b915050612980565b506065546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009173ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015612c4a57600080fd5b505afa158015612c5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c829190613a65565b90506000612c938383606c54612f5c565b905082606c6000828254612ca79190613d71565b9091555050606554612cd09073ffffffffffffffffffffffffffffffffffffffff163383613051565b7f95a8789c26436cc55b5951f117195be05dfa3022c619a84c1449f83f9cf870683387604051612d01929190613be5565b60405180910390a1612d1161339c565b50506065546040517f1da24f3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169250631da24f3e91506024016122d0565b600054610100900460ff1680612d84575060005460ff16155b612e10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff16158015612e4f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b612e57613433565b612e5f613547565b80156125c657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b606083612e9d8484613634565b604051602001612eae929190613ae3565b60405160208183030381529060405290505b9392505050565b606083612ed48484613634565b604051602001612eae929190613b64565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060001415612fdc57838281612fd2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b0492505050612ec0565b808411612fe857600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916130e89190613ac7565b6000604051808303816000865af19150503d8060008114613125576040519150601f19603f3d011682016040523d82523d6000602084013e61312a565b606091505b5091509150818015613154575080511580613154575080806020019051810190613154919061397f565b6131e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c656400000000000000000000000000000000000000606482015260840161041e565b5050505050565b60008183106131f65781612ec0565b5090919050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161329c9190613ac7565b6000604051808303816000865af19150503d80600081146132d9576040519150601f19603f3d011682016040523d82523d6000602084013e6132de565b606091505b5091509150818015613308575080511580613308575080806020019051810190613308919061397f565b613394576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c6564000000000000000000000000000000606482015260840161041e565b505050505050565b6402540be400606c541015611091576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f426f6e64436f6e74726f6c6c65723a204578706563746564206d696e696d756d60448201527f2076616c69642064656274000000000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff168061344c575060005460ff16155b6134d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff16158015612e5f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661010117905580156125c657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b600054610100900460ff1680613560575060005460ff16155b6135ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161041e565b600054610100900460ff1615801561362b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b612e5f33612ee5565b604080518082018252601981527f4142434445464748494a4b4c4d4e4f505152535455565758590000000000000060208201528151600180825281840190935260609260009190602082018180368337019050509050613695600185613d71565b85141561372b577f5a00000000000000000000000000000000000000000000000000000000000000816000815181106136f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506137d9565b818581518110613764577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602001015160f81c60f81b816000815181106137a9577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b949350505050565b600082601f8301126137f1578081fd5b8135602067ffffffffffffffff82111561380d5761380d613e20565b8160051b61381c828201613c94565b838152828101908684018388018501891015613836578687fd5b8693505b8584101561385857803583526001939093019291840191840161383a565b50979650505050505050565b600060208284031215613875578081fd5b8135612ec081613e4f565b600060208284031215613891578081fd5b8151612ec081613e4f565b60008060008060008060c087890312156138b4578182fd5b86356138bf81613e4f565b955060208701356138cf81613e4f565b945060408701356138df81613e4f565b9350606087013567ffffffffffffffff8111156138fa578283fd5b61390689828a016137e1565b9350506080870135915060a087013590509295509295509295565b60008060408385031215613933578182fd5b823561393e81613e4f565b946020939093013593505050565b60006020828403121561395d578081fd5b813567ffffffffffffffff811115613973578182fd5b6137d9848285016137e1565b600060208284031215613990578081fd5b81518015158114612ec0578182fd5b6000602082840312156139b0578081fd5b815167ffffffffffffffff808211156139c7578283fd5b818401915084601f8301126139da578283fd5b8151818111156139ec576139ec613e20565b613a1d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613c94565b9150808252856020828501011115613a33578384fd5b613a44816020840160208601613d88565b50949350505050565b600060208284031215613a5e578081fd5b5035919050565b600060208284031215613a76578081fd5b5051919050565b60008151808452613a95816020860160208601613d88565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008251613ad9818460208701613d88565b9190910192915050565b60007f427574746f6e5472616e6368652000000000000000000000000000000000000082528351613b1b81600e850160208801613d88565b7f2000000000000000000000000000000000000000000000000000000000000000600e918401918201528351613b5881600f840160208801613d88565b01600f01949350505050565b60007f5452414e4348452d00000000000000000000000000000000000000000000000082528351613b9c816008850160208801613d88565b7f2d000000000000000000000000000000000000000000000000000000000000006008918401918201528351613bd9816009840160208801613d88565b01600901949350505050565b60006040820173ffffffffffffffffffffffffffffffffffffffff8516835260206040818501528185518084526060860191508287019350845b81811015613c3b57845183529383019391830191600101613c1f565b5090979650505050505050565b600060608252613c5b6060830186613a7d565b8281036020840152613c6d8186613a7d565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613cdb57613cdb613e20565b604052919050565b60008219821115613cf657613cf6613df1565b500190565b600082613d2f577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613d6c57613d6c613df1565b500290565b600082821015613d8357613d83613df1565b500390565b60005b83811015613da3578181015183820152602001613d8b565b83811115613db2576000848401525b50505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613dea57613dea613df1565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146125c657600080fdfea164736f6c6343000803000a", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/spot-contracts/hardhat.config.ts b/spot-contracts/hardhat.config.ts index e0f1fb42..25ab7126 100644 --- a/spot-contracts/hardhat.config.ts +++ b/spot-contracts/hardhat.config.ts @@ -1,7 +1,7 @@ import { HardhatUserConfig } from "hardhat/config"; import { Wallet } from "ethers"; -import "@nomiclabs/hardhat-ethers"; +import "@nomicfoundation/hardhat-ethers"; import "@nomicfoundation/hardhat-chai-matchers"; import "@nomicfoundation/hardhat-verify"; import "@openzeppelin/hardhat-upgrades"; @@ -53,7 +53,7 @@ export default { settings: { optimizer: { enabled: true, - runs: 750, + runs: 40, }, }, }, diff --git a/spot-contracts/package.json b/spot-contracts/package.json index 28a57f1d..5e4483df 100644 --- a/spot-contracts/package.json +++ b/spot-contracts/package.json @@ -16,22 +16,21 @@ "test": "yarn hardhat test test/*.ts test/**/*.ts" }, "dependencies": { - "@openzeppelin/contracts-upgradeable": "^4.7.3" + "@openzeppelin/contracts-upgradeable": "4.7.3" }, "devDependencies": { - "@defi-wonderland/smock": "^2.3.4", "@ethersproject/abi": "^5.6.4", "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/bytes": "^5.6.1", "@ethersproject/providers": "^5.6.8", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", - "@nomicfoundation/hardhat-verify": "^1.1.0", - "@nomiclabs/hardhat-ethers": "^2.2.1", - "@nomiclabs/hardhat-waffle": "^2.0.3", - "@openzeppelin/hardhat-upgrades": "^1.19.0", + "@nomicfoundation/hardhat-chai-matchers": "latest", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-verify": "latest", + "@nomiclabs/hardhat-waffle": "^2.0.6", + "@openzeppelin/hardhat-upgrades": "^3.0.4", "@openzeppelin/upgrades-core": "latest", - "@typechain/ethers-v5": "^10.1.0", + "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.3.1", "@types/mocha": "^9.1.1", @@ -51,11 +50,12 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.0.0", "eslint-plugin-unused-imports": "^3.0.0", - "ethereum-waffle": "^3.4.4", - "ethers": "^5.6.9", - "ganache-cli": "^6.12.2", - "hardhat": "^2.19.4", - "hardhat-gas-reporter": "^1.0.9", + "ethereum-waffle": "latest", + "ethers": "^6.6.0", + "ethers-v5": "npm:ethers@^5.7.0", + "ganache-cli": "latest", + "hardhat": "^2.23.0", + "hardhat-gas-reporter": "latest", "lodash": "^4.17.21", "prettier": "^2.7.1", "prettier-plugin-solidity": "^1.0.0-dev.23", @@ -66,6 +66,6 @@ "typescript": "^4.7.4" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.0.0" } } diff --git a/spot-contracts/tasks/deploy/ampl.ts b/spot-contracts/tasks/deploy/ampl.ts index ffa00829..df245c3b 100644 --- a/spot-contracts/tasks/deploy/ampl.ts +++ b/spot-contracts/tasks/deploy/ampl.ts @@ -12,7 +12,6 @@ task("deploy:MockAMPL") const UFragments = await getContractFactoryFromExternalArtifacts(hre.ethers, "UFragments"); const ampl = (await UFragments.connect(signer).deploy()).connect(signer); - await ampl.deployed(); const tx1 = await ampl["initialize(address)"](signerAddress); await tx1.wait(); @@ -23,7 +22,7 @@ task("deploy:MockAMPL") if (args.verify) { try { await hre.run("verify:contract", { - address: ampl.address, + address: ampl.target, }); } catch (e) { console.log("Unable to verify on etherscan", e); @@ -32,5 +31,5 @@ task("deploy:MockAMPL") console.log("Skipping verification"); } - console.log("AMPL", ampl.address); + console.log("AMPL", ampl.target); }); diff --git a/spot-contracts/tasks/deploy/buttonwood.ts b/spot-contracts/tasks/deploy/buttonwood.ts index c2e1693b..55cf8220 100644 --- a/spot-contracts/tasks/deploy/buttonwood.ts +++ b/spot-contracts/tasks/deploy/buttonwood.ts @@ -11,23 +11,20 @@ task("deploy:BondFactory") console.log("Signer", await (await hre.ethers.getSigners())[0].getAddress()); const BondController = await getContractFactoryFromExternalArtifacts(hre.ethers, "BondController"); const bondController = await BondController.deploy(); - await bondController.deployed(); - console.log("Bond controller", bondController.address); + console.log("Bond controller", bondController.target); const Tranche = await getContractFactoryFromExternalArtifacts(hre.ethers, "Tranche"); const tranche = await Tranche.deploy(); - await tranche.deployed(); - console.log("Tranche", tranche.address); + console.log("Tranche", tranche.target); const TrancheFactory = await getContractFactoryFromExternalArtifacts(hre.ethers, "TrancheFactory"); - const trancheFactory = await TrancheFactory.deploy(tranche.address); - await trancheFactory.deployed(); - console.log("Tranche Factory", trancheFactory.address); + const trancheFactory = await TrancheFactory.deploy(tranche.target); + console.log("Tranche Factory", trancheFactory.target); await tranche["init(string,string,address,address)"]("IMPLEMENTATION", "IMPL", DUMMY_ADDRESS, DUMMY_ADDRESS); await bondController.init( - trancheFactory.address, - tranche.address, + trancheFactory.target, + tranche.target, DUMMY_ADDRESS, [200, 300, 500], hre.ethers.constants.MaxUint256, @@ -35,22 +32,21 @@ task("deploy:BondFactory") ); const BondFactory = await getContractFactoryFromExternalArtifacts(hre.ethers, "BondFactory"); - const bondFactory = await BondFactory.deploy(bondController.address, trancheFactory.address); - await bondFactory.deployed(); - console.log("Bond Factory", bondFactory.address); + const bondFactory = await BondFactory.deploy(bondController.target, trancheFactory.target); + console.log("Bond Factory", bondFactory.target); if (args.verify) { try { - await hre.run("verify:Template", { address: bondController.address }); - await hre.run("verify:Template", { address: tranche.address }); + await hre.run("verify:Template", { address: bondController.target }); + await hre.run("verify:Template", { address: tranche.target }); await hre.run("verify:TrancheFactory", { - address: trancheFactory.address, - template: tranche.address, + address: trancheFactory.target, + template: tranche.target, }); await hre.run("verify:BondFactory", { - address: bondFactory.address, - template: bondController.address, - trancheFactory: trancheFactory.address, + address: bondFactory.target, + template: bondController.target, + trancheFactory: trancheFactory.target, }); } catch (e) { console.log("Unable to verify on etherscan", e); diff --git a/spot-contracts/tasks/deploy/perp.ts b/spot-contracts/tasks/deploy/perp.ts index b6e3f5c6..b6a83251 100644 --- a/spot-contracts/tasks/deploy/perp.ts +++ b/spot-contracts/tasks/deploy/perp.ts @@ -42,14 +42,14 @@ task("deploy:BondIssuer") if (verify) { await sleep(30); await hre.run("verify:contract", { - address: bondIssuer.address, + address: bondIssuer.target, constructorArguments: [bondFactoryAddress, collateralTokenAddress], }); } else { console.log("Skipping verification"); } - console.log("Bond issuer", bondIssuer.address); + console.log("Bond issuer", bondIssuer.target); }); task("deploy:PerpSystem") @@ -67,19 +67,16 @@ task("deploy:PerpSystem") const FeePolicy = await hre.ethers.getContractFactory("FeePolicy"); const feePolicy = await hre.upgrades.deployProxy(FeePolicy.connect(deployer)); - await feePolicy.deployed(); const PerpetualTranche = await hre.ethers.getContractFactory("PerpetualTranche"); const perp = await hre.upgrades.deployProxy(PerpetualTranche.connect(deployer)); - await perp.deployed(); const RolloverVault = await hre.ethers.getContractFactory("RolloverVault"); const vault = await hre.upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.deployed(); - console.log("perp", perp.address); - console.log("vault", vault.address); - console.log("feePolicy", feePolicy.address); + console.log("perp", perp.target); + console.log("vault", vault.target); + console.log("feePolicy", feePolicy.target); console.log("fee policy init"); await (await feePolicy.init()).wait(); @@ -90,32 +87,32 @@ task("deploy:PerpSystem") perpSymbol, collateralTokenAddress, bondIssuerAddress, - feePolicy.address, + feePolicy.target, ); await perpInitTx.wait(); console.log("vault init"); - const vaultInitTx = await vault.init(vaultName, vaultSymbol, perp.address, feePolicy.address); + const vaultInitTx = await vault.init(vaultName, vaultSymbol, perp.target, feePolicy.target); await vaultInitTx.wait(); console.log("point perp to vault"); - await (await perp.updateVault(vault.address)).wait(); + await (await perp.updateVault(vault.target)).wait(); if (verify) { await sleep(30); // We just need to verify the proxy once await hre.run("verify:contract", { - address: feePolicy.address, + address: feePolicy.target, }); // Verifying implementations await hre.run("verify:contract", { - address: await getImplementationAddress(hre.ethers.provider, feePolicy.address), + address: await getImplementationAddress(hre.ethers.provider, feePolicy.target), }); await hre.run("verify:contract", { - address: await getImplementationAddress(hre.ethers.provider, perp.address), + address: await getImplementationAddress(hre.ethers.provider, perp.target), }); await hre.run("verify:contract", { - address: await getImplementationAddress(hre.ethers.provider, vault.address), + address: await getImplementationAddress(hre.ethers.provider, vault.target), }); } else { console.log("Skipping verification"); @@ -129,13 +126,12 @@ task("deploy:Router") const RouterV2 = await hre.ethers.getContractFactory("RouterV2"); const router = await RouterV2.deploy(); - await router.deployed(); - console.log("RouterV2", router.address); + console.log("RouterV2", router.target); if (args.verify) { await sleep(30); await hre.run("verify:contract", { - address: router.address, + address: router.target, }); } else { console.log("Skipping verification"); @@ -152,16 +148,15 @@ task("deploy:FeePolicy") const feePolicy = await hre.upgrades.deployProxy(FeePolicy.connect(deployer), [], { initializer: "init()", }); - await feePolicy.deployed(); - console.log("feePolicy", feePolicy.address); + console.log("feePolicy", feePolicy.target); if (args.verify) { await sleep(30); await hre.run("verify:contract", { - address: feePolicy.address, + address: feePolicy.target, }); await hre.run("verify:contract", { - address: await getImplementationAddress(hre.ethers.provider, feePolicy.address), + address: await getImplementationAddress(hre.ethers.provider, feePolicy.target), }); } else { console.log("Skipping verification"); diff --git a/spot-contracts/tasks/deploy/vaults.ts b/spot-contracts/tasks/deploy/vaults.ts index 436d80bc..c3fa503e 100644 --- a/spot-contracts/tasks/deploy/vaults.ts +++ b/spot-contracts/tasks/deploy/vaults.ts @@ -15,12 +15,11 @@ task("deploy:RolloverVault") const RolloverVault = await hre.ethers.getContractFactory("RolloverVault"); const vault = await hre.upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.deployed(); - const implAddress = await getImplementationAddress(hre.ethers.provider, vault.address); + const implAddress = await getImplementationAddress(hre.ethers.provider, vault.target); console.log("perp", perpAddress); - console.log("vault", vault.address); + console.log("vault", vault.target); console.log("vaultImpl", implAddress); const initTx = await vault.init(name, symbol, perpAddress); diff --git a/spot-contracts/tasks/ops/perp.ts b/spot-contracts/tasks/ops/perp.ts index b3fc6569..f9a85970 100644 --- a/spot-contracts/tasks/ops/perp.ts +++ b/spot-contracts/tasks/ops/perp.ts @@ -1,7 +1,6 @@ import { getAdminAddress, getImplementationAddress } from "@openzeppelin/upgrades-core"; import { task, types } from "hardhat/config"; import { TaskArguments } from "hardhat/types"; -import { utils } from "ethers"; task("ops:perp:info") .addPositionalParam("perpAddress", "the address of the perp contract", undefined, types.string, false) @@ -13,90 +12,90 @@ task("ops:perp:info") const percDecimals = await perp.PERC_DECIMALS(); const bondIssuer = await hre.ethers.getContractAt("BondIssuer", await perp.bondIssuer()); - const latestBond = await hre.ethers.getContractAt("IBondController", await bondIssuer.callStatic.getLatestBond()); + const latestBond = await hre.ethers.getContractAt("IBondController", await bondIssuer.getLatestBond.staticCall()); const collateralToken = await hre.ethers.getContractAt("MockERC20", await perp.underlying()); const feePolicy = await hre.ethers.getContractAt("FeePolicy", await perp.feePolicy()); - const depositBond = await hre.ethers.getContractAt("IBondController", await perp.callStatic.getDepositBond()); - const issued = (await hre.ethers.provider.getCode(depositBond.address)) !== "0x"; + const depositBond = await hre.ethers.getContractAt("IBondController", await perp.getDepositBond.staticCall()); + const issued = (await hre.ethers.provider.getCode(depositBond.target)) !== "0x"; const perpSupply = await perp.totalSupply(); - const perpTVL = await perp.callStatic.getTVL(); - const perpPrice = perpSupply.gt("0") ? perpTVL.mul(1000).div(perpSupply) : 0; + const perpTVL = await perp.getTVL.staticCall(); + const perpPrice = perpSupply > 0n ? (perpTVL * 1000n) / perpSupply : 0; const proxyAdminAddress = await getAdminAddress(hre.ethers.provider, perpAddress); const implAddress = await getImplementationAddress(hre.ethers.provider, perpAddress); console.log("---------------------------------------------------------------"); - console.log("BondIssuer:", bondIssuer.address); + console.log("BondIssuer:", bondIssuer.target); console.log("bondFactory:", await bondIssuer.bondFactory()); console.log("collateral:", await bondIssuer.collateral()); - console.log("issuedCount:", utils.formatUnits(await bondIssuer.issuedCount()), 0); - console.log("maxMaturityDuration:", utils.formatUnits(await bondIssuer.maxMaturityDuration(), 0)); - console.log("minIssueTimeIntervalSec:", utils.formatUnits(await bondIssuer.minIssueTimeIntervalSec(), 0)); - console.log("issueWindowOffsetSec:", utils.formatUnits(await bondIssuer.issueWindowOffsetSec(), 0)); + console.log("issuedCount:", hre.ethers.formatUnits(await bondIssuer.issuedCount()), 0); + console.log("maxMaturityDuration:", hre.ethers.formatUnits(await bondIssuer.maxMaturityDuration(), 0)); + console.log("minIssueTimeIntervalSec:", hre.ethers.formatUnits(await bondIssuer.minIssueTimeIntervalSec(), 0)); + console.log("issueWindowOffsetSec:", hre.ethers.formatUnits(await bondIssuer.issueWindowOffsetSec(), 0)); let i = 0; while (true) { try { - console.log(`trancheRatios(${i}):`, utils.formatUnits(await bondIssuer.trancheRatios(i), 3)); + console.log(`trancheRatios(${i}):`, hre.ethers.formatUnits(await bondIssuer.trancheRatios(i), 3)); i++; } catch (e) { break; } } - console.log("lastIssueWindowTimestamp:", utils.formatUnits(await bondIssuer.lastIssueWindowTimestamp(), 0)); - console.log("latestBond:", latestBond.address); + console.log("lastIssueWindowTimestamp:", hre.ethers.formatUnits(await bondIssuer.lastIssueWindowTimestamp(), 0)); + console.log("latestBond:", latestBond.target); console.log("---------------------------------------------------------------"); - console.log("feePolicy:", feePolicy.address); + console.log("feePolicy:", feePolicy.target); console.log("owner", await feePolicy.owner()); - console.log("perpMintFeePerc:", utils.formatUnits(await feePolicy.perpMintFeePerc(), percDecimals)); - console.log("perpBurnFeePerc:", utils.formatUnits(await feePolicy.perpBurnFeePerc(), percDecimals)); + console.log("perpMintFeePerc:", hre.ethers.formatUnits(await feePolicy.perpMintFeePerc(), percDecimals)); + console.log("perpBurnFeePerc:", hre.ethers.formatUnits(await feePolicy.perpBurnFeePerc(), percDecimals)); const r = await feePolicy.perpRolloverFee(); - console.log("perpRolloverFeeLower:", utils.formatUnits(r.lower, percDecimals)); - console.log("perpRolloverFeeUpper:", utils.formatUnits(r.upper, percDecimals)); - console.log("perpRolloverFeeGrowth:", utils.formatUnits(r.growth, percDecimals)); + console.log("minRolloverFeePerc:", hre.ethers.formatUnits(r.minRolloverFeePerc, percDecimals)); + console.log("perpDebasementSlope:", hre.ethers.formatUnits(r.perpDebasementSlope, percDecimals)); + console.log("perpEnrichmentSlope:", hre.ethers.formatUnits(r.perpEnrichmentSlope, percDecimals)); console.log("---------------------------------------------------------------"); - console.log("PerpetualTranche:", perp.address); + console.log("PerpetualTranche:", perp.target); console.log("proxyAdmin:", proxyAdminAddress); console.log("implementation:", implAddress); console.log("owner:", await perp.owner()); console.log("keeper:", await perp.keeper()); console.log("paused:", await perp.paused()); - console.log("collateralToken:", collateralToken.address); + console.log("collateralToken:", collateralToken.target); console.log("---------------------------------------------------------------"); console.log(`maturityTolarance: [${await perp.minTrancheMaturitySec()}, ${await perp.maxTrancheMaturitySec()}]`); - console.log("maxSupply:", utils.formatUnits(await perp.maxSupply(), await perp.decimals())); + console.log("maxSupply:", hre.ethers.formatUnits(await perp.maxSupply(), await perp.decimals())); console.log( "maxDepositTrancheValuePerc:", - utils.formatUnits(await perp.maxDepositTrancheValuePerc(), percDecimals), + hre.ethers.formatUnits(await perp.maxDepositTrancheValuePerc(), percDecimals), ); console.log("---------------------------------------------------------------"); - console.log("depositBond:", depositBond.address); + console.log("depositBond:", depositBond.target); console.log("issued:", issued); - console.log("TotalSupply:", utils.formatUnits(perpSupply, perpDecimals)); - console.log("TVL:", utils.formatUnits(perpTVL, perpDecimals)); - console.log("deviationRatio:", utils.formatUnits(await perp.callStatic.deviationRatio(), percDecimals)); + console.log("TotalSupply:", hre.ethers.formatUnits(perpSupply, perpDecimals)); + console.log("TVL:", hre.ethers.formatUnits(perpTVL, perpDecimals)); + console.log("deviationRatio:", hre.ethers.formatUnits(await perp.deviationRatio.staticCall(), percDecimals)); console.log("---------------------------------------------------------------"); console.log("Reserve:"); - const reserveCount = (await perp.callStatic.getReserveCount()).toNumber(); - const upForRollover = await perp.callStatic.getReserveTokensUpForRollover(); + const reserveCount = await perp.getReserveCount.staticCall(); + const upForRollover = await perp.getReserveTokensUpForRollover.staticCall(); const data = []; for (let i = 0; i < reserveCount; i++) { - const tokenAddress = await perp.callStatic.getReserveAt(i); - const balance = await perp.callStatic.getReserveTokenBalance(tokenAddress); - const value = await perp.callStatic.getReserveTokenValue(tokenAddress); - const price = balance.gt("0") ? value.mul(1000).div(balance) : 0; + const tokenAddress = await perp.getReserveAt.staticCall(i); + const balance = await perp.getReserveTokenBalance.staticCall(tokenAddress); + const value = await perp.getReserveTokenValue.staticCall(tokenAddress); + const price = balance > 0n ? (value * balance * 1000) / 10n ** perpDecimals / 10n ** percDecimals : 0n; data.push({ token: tokenAddress, - balance: utils.formatUnits(balance, await perp.decimals()), - price: utils.formatUnits(price, 3), - upForRollover: balance.gt("0") && upForRollover.find(t => t === tokenAddress) !== undefined, + balance: hre.ethers.formatUnits(balance, await perp.decimals()), + price: hre.ethers.formatUnits(price, 3), + upForRollover: balance > 0n && upForRollover.find(t => t === tokenAddress) !== undefined, }); } console.table(data); console.log("reserveCount:", reserveCount); - console.log("price:", utils.formatUnits(perpPrice, 3)); + console.log("price:", hre.ethers.formatUnits(perpPrice, 3)); console.log("---------------------------------------------------------------"); }); @@ -190,9 +189,9 @@ task("ops:perp:trancheAndDeposit") const bondIssuer = await hre.ethers.getContractAt("BondIssuer", await perp.bondIssuer()); const collateralToken = await hre.ethers.getContractAt("MockERC20", await bondIssuer.collateral()); - const fixedPtCollateralAmount = utils.parseUnits(collateralAmount, await collateralToken.decimals()); - const [depositBondAddress, depositTranches] = await router.callStatic.previewTranche( - perp.address, + const fixedPtCollateralAmount = hre.ethers.parseUnits(collateralAmount, await collateralToken.decimals()); + const [depositBondAddress, depositTranches] = await router.previewTranche.staticCall( + perp.target, fixedPtCollateralAmount, ); console.log(depositBondAddress, depositTranches); @@ -202,18 +201,18 @@ task("ops:perp:trancheAndDeposit") console.log( "tranches(0):", depositTranches[0].token, - utils.formatUnits(depositTranches[0].amount.toString(), await collateralToken.decimals()), + hre.ethers.formatUnits(depositTranches[0].amount.toString(), await collateralToken.decimals()), ); console.log( "tranches(1):", depositTranches[1].token, - utils.formatUnits(depositTranches[1].amount.toString(), await collateralToken.decimals()), + hre.ethers.formatUnits(depositTranches[1].amount.toString(), await collateralToken.decimals()), ); console.log("---------------------------------------------------------------"); console.log("Preview mint:", collateralAmount); - const totalMintAmt = await perp.callStatic.computeMintAmt(depositTranches[0].token, depositTranches[0].amount); - console.log("mintAmt", utils.formatUnits(totalMintAmt, await perp.decimals())); + const totalMintAmt = await perp.computeMintAmt.staticCall(depositTranches[0].token, depositTranches[0].amount); + console.log("mintAmt", hre.ethers.formatUnits(totalMintAmt, await perp.decimals())); if (totalMintAmt.eq("0")) { throw Error("No perp minted"); } @@ -225,9 +224,9 @@ task("ops:perp:trancheAndDeposit") console.log("Signer", signerAddress); console.log("Approving router to spend tokens:"); - const allowance = await collateralToken.allowance(signerAddress, router.address); + const allowance = await collateralToken.allowance(signerAddress, router.target); if (allowance.lt(fixedPtCollateralAmount)) { - const tx1 = await collateralToken.connect(signer).approve(router.address, fixedPtCollateralAmount); + const tx1 = await collateralToken.connect(signer).approve(router.target, fixedPtCollateralAmount); await tx1.wait(); console.log("Tx", tx1.hash); } @@ -235,11 +234,11 @@ task("ops:perp:trancheAndDeposit") console.log("Tranche and deposit:"); const tx2 = await router .connect(signer) - .trancheAndDeposit(perp.address, depositBondAddress, fixedPtCollateralAmount); + .trancheAndDeposit(perp.target, depositBondAddress, fixedPtCollateralAmount); await tx2.wait(); console.log("Tx", tx2.hash); - console.log("Signer balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); + console.log("Signer balance", hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); }); task("ops:perp:redeem") @@ -252,18 +251,18 @@ task("ops:perp:redeem") const router = await hre.ethers.getContractAt("RouterV2", routerAddress); const perp = await hre.ethers.getContractAt("PerpetualTranche", perpAddress); - const fixedPtAmount = utils.parseUnits(amount, await perp.decimals()); + const fixedPtAmount = hre.ethers.parseUnits(amount, await perp.decimals()); console.log("---------------------------------------------------------------"); console.log("Preview redeem:", amount); - const reserveTokens = await perp.callStatic.computeRedemptionAmts(fixedPtAmount); + const reserveTokens = await perp.computeRedemptionAmts.staticCall(fixedPtAmount); console.log("burnAmt", amount); console.log("reserve token redeemed"); for (let i = 0; i < reserveTokens.length; i++) { console.log( `reserve(${i}):`, reserveTokens[i].token, - utils.formatUnits(reserveTokens[i].amount.toString(), await perp.decimals()), + hre.ethers.formatUnits(reserveTokens[i].amount.toString(), await perp.decimals()), ); } @@ -274,8 +273,8 @@ task("ops:perp:redeem") console.log("Signer", signerAddress); console.log("Approving router to spend tokens:"); - if ((await perp.allowance(signerAddress, router.address)).lt(fixedPtAmount)) { - const tx1 = await perp.connect(signer).approve(router.address, fixedPtAmount); + if ((await perp.allowance(signerAddress, router.target)).lt(fixedPtAmount)) { + const tx1 = await perp.connect(signer).approve(router.target, fixedPtAmount); await tx1.wait(); console.log("Tx", tx1.hash); } @@ -285,5 +284,5 @@ task("ops:perp:redeem") await tx2.wait(); console.log("Tx", tx2.hash); - console.log("Signer balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); + console.log("Signer balance", hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); }); diff --git a/spot-contracts/tasks/ops/tranche.ts b/spot-contracts/tasks/ops/tranche.ts index ecbc5880..0db1d67f 100644 --- a/spot-contracts/tasks/ops/tranche.ts +++ b/spot-contracts/tasks/ops/tranche.ts @@ -10,7 +10,7 @@ async function matureBond(bond: Contract, signer: Signer) { } try { console.log("Invoking Mature"); - await bond.connect(signer).callStatic.mature(); + await bond.connect(signer).mature.staticCall(); const tx = await bond.connect(signer).mature(); await tx.wait(); console.log("Tx:", tx.hash); @@ -103,8 +103,8 @@ task("ops:redeemTranches") for (let j = 0; j < bt.length; j++) { const b = await bt[j][0].balanceOf(signerAddress); if (b.gt(0)) { - console.log("Redeeming mature tranche", bt[j][0].address); - const tx = await bond.connect(signer).redeemMature(bt[j][0].address, b); + console.log("Redeeming mature tranche", bt[j][0].target); + const tx = await bond.connect(signer).redeemMature(bt[j][0].target, b); await tx.wait(); console.log("Tx:", tx.hash); } @@ -133,9 +133,9 @@ task("ops:preview_tx:redeemTranches") const txs: ProposedTransaction[] = []; const bondIssuer = await hre.ethers.getContractAt("BondIssuer", bondIssuerAddress); - const issuedCount = await bondIssuer.callStatic.issuedCount(); + const issuedCount = await bondIssuer.issuedCount.staticCall(); for (let i = issuedCount - 1; i > 0 && issuedCount - 1 - i < depth; i--) { - const bondAddress = await bondIssuer.callStatic.issuedBondAt(i); + const bondAddress = await bondIssuer.issuedBondAt.staticCall(i); const bond = await hre.ethers.getContractAt("IBondController", bondAddress); const bt = await getTranches(hre, bond); @@ -148,7 +148,7 @@ task("ops:preview_tx:redeemTranches") txs.push({ contract: bond, method: "redeemMature", - args: [bt[j][0].address, b.toString()], + args: [bt[j][0].target, b.toString()], }); } } @@ -168,7 +168,7 @@ task("ops:preview_tx:redeemTranches") console.log("Execute the following transactions"); for (let i = 0; i < txs.length; i++) { - console.log({ to: txs[i].contract.address, method: txs[i].method, args: txs[i].args }); + console.log({ to: txs[i].contract.target, method: txs[i].method, args: txs[i].args }); } console.log("Wrote tx batch to file:", "RedeemBatch.json"); diff --git a/spot-contracts/tasks/ops/vaults.ts b/spot-contracts/tasks/ops/vaults.ts index d54ceac6..e2549e0e 100644 --- a/spot-contracts/tasks/ops/vaults.ts +++ b/spot-contracts/tasks/ops/vaults.ts @@ -1,7 +1,6 @@ import { getAdminAddress, getImplementationAddress } from "@openzeppelin/upgrades-core"; import { task, types } from "hardhat/config"; import { TaskArguments } from "hardhat/types"; -import { BigNumber, utils } from "ethers"; task("ops:vault:info") .addPositionalParam("vaultAddress", "the address of the vault contract", undefined, types.string, false) @@ -23,116 +22,118 @@ task("ops:vault:info") let pokeAvailable = true; try { - await vault.callStatic.recoverAndRedeploy(); + await vault.recoverAndRedeploy.staticCall(); } catch (e) { pokeAvailable = false; } console.log("---------------------------------------------------------------"); - console.log("RolloverVault:", vault.address); + console.log("RolloverVault:", vault.target); console.log("proxyAdmin:", proxyAdminAddress); console.log("implementation:", implAddress); console.log("owner:", await vault.owner()); console.log("paused:", await vault.paused()); - console.log("perp:", perp.address); - console.log("underlying:", underlying.address); - console.log("minDeploymentAmt:", utils.formatUnits(await vault.minDeploymentAmt(), underlyingDecimals)); - console.log("totalSupply:", utils.formatUnits(vaultSupply, vaultDecimals)); + console.log("perp:", perp.target); + console.log("underlying:", underlying.target); + console.log("minDeploymentAmt:", hre.ethers.formatUnits(await vault.minDeploymentAmt(), underlyingDecimals)); + console.log("totalSupply:", hre.ethers.formatUnits(vaultSupply, vaultDecimals)); console.log("pokeAvailable:", pokeAvailable); console.log("---------------------------------------------------------------"); const data = []; - const underlyingBalance = await vault.vaultAssetBalance(underlying.address); + const underlyingBalance = await vault.vaultAssetBalance(underlying.target); data.push({ asset: await underlying.symbol(), - balance: utils.formatUnits(underlyingBalance, underlyingDecimals), + balance: hre.ethers.formatUnits(underlyingBalance, underlyingDecimals), price: "1", }); - const assetCount = (await vault.assetCount()).toNumber(); + const assetCount = Number(await vault.assetCount()); for (let i = 1; i < assetCount; i++) { - const tokenAddress = await vault.callStatic.assetAt(i); + const tokenAddress = await vault.assetAt.staticCall(i); const balance = await vault.vaultAssetBalance(tokenAddress); - const value = await vault.callStatic.getVaultAssetValue(tokenAddress); - const price = value.mul(BigNumber.from(10 ** perpDecimals)).div(balance); + const value = await vault.getVaultAssetValue.staticCall(tokenAddress); + const price = (value * 10n ** perpDecimals) / balance; const token = await hre.ethers.getContractAt("MockERC20", tokenAddress); data.push({ asset: await token.symbol(), - balance: utils.formatUnits(balance, underlyingDecimals), - price: utils.formatUnits(price, perpDecimals), + balance: hre.ethers.formatUnits(balance, underlyingDecimals), + price: hre.ethers.formatUnits(price, perpDecimals), }); } - const perpBalance = await perp.balanceOf(vault.address); + const perpBalance = await perp.balanceOf(vault.target); const perpSupply = await perp.totalSupply(); - const perpTVL = await perp.callStatic.getTVL(); - const perpPrice = perpSupply.gt("0") ? perpTVL.mul(1000).div(perpSupply) : 0; + const perpTVL = await perp.getTVL.staticCall(); + const perpPrice = perpSupply > 0n ? (perpTVL * 1000n) / perpSupply : 0n; data.push({ asset: await perp.symbol(), - balance: utils.formatUnits(perpBalance, perpDecimals), - price: utils.formatUnits(perpPrice, 3), + balance: hre.ethers.formatUnits(perpBalance, perpDecimals), + price: hre.ethers.formatUnits(perpPrice, 3), }); console.table(data); console.log("---------------------------------------------------------------"); const feeOne = await feePolicy.ONE(); const feeDecimals = await feePolicy.decimals(); - const vaultTVL = await vault.callStatic.getTVL(); - const seniorTR = await perp.callStatic.getDepositTrancheRatio(); - const juniorTR = BigNumber.from("1000").sub(seniorTR); - const subscriptionRatio = vaultTVL.mul(seniorTR).mul(feeOne).div(perpTVL).div(juniorTR); + const vaultTVL = await vault.getTVL.staticCall(); + const seniorTR = await perp.getDepositTrancheRatio.staticCall(); + const juniorTR = 1000n - seniorTR; + const subscriptionRatio = (vaultTVL * seniorTR * feeOne) / perpTVL / juniorTR; const targetSubscriptionRatio = await feePolicy.targetSubscriptionRatio(); - const expectedVaultTVL = targetSubscriptionRatio.mul(perpTVL).mul(juniorTR).div(seniorTR).div(feeOne); + const expectedVaultTVL = (targetSubscriptionRatio * perpTVL * juniorTR) / seniorTR / feeOne; const deviationRatio = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]([ perpTVL, vaultTVL, seniorTR, ]); - console.log("perpTVL:", utils.formatUnits(perpTVL, underlyingDecimals)); - console.log("vaultTVL:", utils.formatUnits(vaultTVL, underlyingDecimals)); - console.log("expectedVaultTVL:", utils.formatUnits(expectedVaultTVL, underlyingDecimals)); - console.log("seniorTR:", utils.formatUnits(seniorTR, 3)); - console.log("juniorTR:", utils.formatUnits(juniorTR, 3)); - console.log("subscriptionRatio:", utils.formatUnits(subscriptionRatio, feeDecimals)); - console.log("targetSubscriptionRatio:", utils.formatUnits(targetSubscriptionRatio, feeDecimals)); - console.log("targetDeviationRatio:", utils.formatUnits(feeOne, feeDecimals)); - console.log( - "deviationRatioBoundLower:", - utils.formatUnits(await feePolicy.deviationRatioBoundLower(), feeDecimals), - ); - console.log( - "deviationRatioBoundUpper:", - utils.formatUnits(await feePolicy.deviationRatioBoundUpper(), feeDecimals), - ); - console.log("deviationRatio:", utils.formatUnits(deviationRatio, feeDecimals)); + console.log("perpTVL:", hre.ethers.formatUnits(perpTVL, underlyingDecimals)); + console.log("vaultTVL:", hre.ethers.formatUnits(vaultTVL, underlyingDecimals)); + console.log("expectedVaultTVL:", hre.ethers.formatUnits(expectedVaultTVL, underlyingDecimals)); + console.log("seniorTR:", hre.ethers.formatUnits(seniorTR, 3)); + console.log("juniorTR:", hre.ethers.formatUnits(juniorTR, 3)); + console.log("subscriptionRatio:", hre.ethers.formatUnits(subscriptionRatio, feeDecimals)); + console.log("targetSubscriptionRatio:", hre.ethers.formatUnits(targetSubscriptionRatio, feeDecimals)); + console.log("targetDeviationRatio:", hre.ethers.formatUnits(feeOne, feeDecimals)); + + const drHardBound = await feePolicy.drHardBound(); + console.log("deviationRatioBoundLower:", hre.ethers.formatUnits(drHardBound.lower, feeDecimals)); + console.log("deviationRatioBoundUpper:", hre.ethers.formatUnits(drHardBound.upper, feeDecimals)); + console.log("deviationRatio:", hre.ethers.formatUnits(deviationRatio, feeDecimals)); console.log("---------------------------------------------------------------"); - console.log("feePolicy:", feePolicy.address); + console.log("feePolicy:", feePolicy.target); console.log("owner", await feePolicy.owner()); - console.log("computeVaultMintFeePerc:", utils.formatUnits(await feePolicy.computeVaultMintFeePerc(), 8)); - console.log("computeVaultBurnFeePerc:", utils.formatUnits(await feePolicy.computeVaultBurnFeePerc(), 8)); + console.log("computeVaultMintFeePerc:", hre.ethers.formatUnits(await feePolicy.computeVaultMintFeePerc(), 8)); + console.log("computeVaultBurnFeePerc:", hre.ethers.formatUnits(await feePolicy.computeVaultBurnFeePerc(), 8)); console.log( "computeUnderlyingToPerpVaultSwapFeePerc:", - utils.formatUnits(await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(deviationRatio, deviationRatio), 8), + hre.ethers.formatUnits( + await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(deviationRatio, deviationRatio), + 8, + ), ); console.log( "computePerpToUnderlyingVaultSwapFeePerc:", - utils.formatUnits(await feePolicy.computePerpToUnderlyingVaultSwapFeePerc(deviationRatio, deviationRatio), 8), + hre.ethers.formatUnits( + await feePolicy.computePerpToUnderlyingVaultSwapFeePerc(deviationRatio, deviationRatio), + 8, + ), ); console.log("---------------------------------------------------------------"); console.log("Swap slippage"); try { - const buy1000Perps = await vault.callStatic.computeUnderlyingToPerpSwapAmt( - utils.parseUnits("1000", perpDecimals), + const buy1000Perps = await vault.computeUnderlyingToPerpSwapAmt.staticCall( + hre.ethers.parseUnits("1000", perpDecimals), ); - console.log("Swap 1000 underlying for perps: ", utils.formatUnits(buy1000Perps[0], perpDecimals)); + console.log("Swap 1000 underlying for perps: ", hre.ethers.formatUnits(buy1000Perps[0], perpDecimals)); } catch { console.log("Swap underlying for perps disabled"); } try { - const sell1000Perps = await vault.callStatic.computePerpToUnderlyingSwapAmt( - utils.parseUnits("1000", perpDecimals), + const sell1000Perps = await vault.computePerpToUnderlyingSwapAmt.staticCall( + hre.ethers.parseUnits("1000", perpDecimals), ); - console.log("PerpPrice:", utils.formatUnits(perpPrice, 3)); - console.log("Sell 1000 perps for underlying", utils.formatUnits(sell1000Perps[0], perpDecimals)); + console.log("PerpPrice:", hre.ethers.formatUnits(perpPrice, 3)); + console.log("Sell 1000 perps for underlying", hre.ethers.formatUnits(sell1000Perps[0], perpDecimals)); } catch { console.log("Swap perps for underlying disabled"); } @@ -154,23 +155,26 @@ task("ops:vault:deposit") const vault = await hre.ethers.getContractAt("RolloverVault", vaultAddress); const underlying = await hre.ethers.getContractAt("MockERC20", await vault.underlying()); - const fixedPtAmount = utils.parseUnits(underlyingAmount, await underlying.decimals()); + const fixedPtAmount = hre.ethers.parseUnits(underlyingAmount, await underlying.decimals()); const signer = (await hre.ethers.getSigners())[args.fromIdx]; const signerAddress = await signer.getAddress(); console.log("Signer", signerAddress); - console.log("Signer note balance", utils.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals())); + console.log( + "Signer note balance", + hre.ethers.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals()), + ); console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), ); console.log("---------------------------------------------------------------"); console.log("Execution:"); console.log("Approving router to spend tokens:"); - if ((await underlying.allowance(signerAddress, vault.address)).lt(fixedPtAmount)) { - const tx1 = await underlying.connect(signer).approve(vault.address, fixedPtAmount); + if ((await underlying.allowance(signerAddress, vault.target)).lt(fixedPtAmount)) { + const tx1 = await underlying.connect(signer).approve(vault.target, fixedPtAmount); await tx1.wait(); console.log("Tx", tx1.hash); } @@ -180,10 +184,13 @@ task("ops:vault:deposit") await tx3.wait(); console.log("Tx", tx3.hash); - console.log("Signer note balance", utils.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals())); + console.log( + "Signer note balance", + hre.ethers.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals()), + ); console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), ); }); @@ -197,22 +204,25 @@ task("ops:vault:redeem") const vault = await hre.ethers.getContractAt("RolloverVault", vaultAddress); const underlying = await hre.ethers.getContractAt("MockERC20", await vault.underlying()); const underlyingDecimals = await underlying.decimals(); - const fixedPtAmount = utils.parseUnits(amount, await vault.decimals()); + const fixedPtAmount = hre.ethers.parseUnits(amount, await vault.decimals()); const signer = (await hre.ethers.getSigners())[args.fromIdx]; const signerAddress = await signer.getAddress(); console.log("Signer", signerAddress); - console.log("Signer note balance", utils.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals())); + console.log( + "Signer note balance", + hre.ethers.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals()), + ); console.log("---------------------------------------------------------------"); console.log("Preview redeem:", amount); - const redemptions = await vault.callStatic.redeem(fixedPtAmount); + const redemptions = await vault.redeem.staticCall(fixedPtAmount); const redemptionData = []; for (let i = 0; i < redemptions.length; i++) { const token = await hre.ethers.getContractAt("MockERC20", redemptions[i].token); redemptionData.push({ asset: await token.symbol(), - amount: utils.formatUnits(redemptions[i].amount, underlyingDecimals), + amount: hre.ethers.formatUnits(redemptions[i].amount, underlyingDecimals), }); } console.table(redemptionData); @@ -223,7 +233,10 @@ task("ops:vault:redeem") const tx = await vault.connect(signer).redeem(fixedPtAmount); await tx.wait(); console.log("Tx", tx.hash); - console.log("Signer note balance", utils.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals())); + console.log( + "Signer note balance", + hre.ethers.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals()), + ); }); task("ops:vault:recoverAndRedeploy") @@ -296,7 +309,7 @@ task("ops:fee:setSwapFees", "Updates swap fees in fee policy") console.log("Signer", signerAddress); const feePolicy = await hre.ethers.getContractAt("FeePolicy", address); console.log(`Updating both swap fees to ${feePerc}`); - const feeAmtFixedPt = utils.parseUnits(feePerc, await feePolicy.decimals()); + const feeAmtFixedPt = hre.ethers.parseUnits(feePerc, await feePolicy.decimals()); const tx1 = await feePolicy.updateVaultUnderlyingToPerpSwapFeePerc(feeAmtFixedPt); console.log(tx1.hash); @@ -323,23 +336,26 @@ task("ops:vault:swapUnderlyingForPerps") const vault = await hre.ethers.getContractAt("RolloverVault", vaultAddress); const perp = await hre.ethers.getContractAt("PerpetualTranche", await vault.perp()); const underlying = await hre.ethers.getContractAt("MockERC20", await vault.underlying()); - const fixedPtAmount = utils.parseUnits(underlyingAmount, await underlying.decimals()); + const fixedPtAmount = hre.ethers.parseUnits(underlyingAmount, await underlying.decimals()); const signer = (await hre.ethers.getSigners())[args.fromIdx]; const signerAddress = await signer.getAddress(); console.log("Signer", signerAddress); - console.log("Signer perp balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); + console.log( + "Signer perp balance", + hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals()), + ); console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), ); console.log("---------------------------------------------------------------"); console.log("Execution:"); console.log("Approving router to spend tokens:"); - if ((await underlying.allowance(signerAddress, vault.address)).lt(fixedPtAmount)) { - const tx1 = await underlying.connect(signer).approve(vault.address, fixedPtAmount); + if ((await underlying.allowance(signerAddress, vault.target)).lt(fixedPtAmount)) { + const tx1 = await underlying.connect(signer).approve(vault.target, fixedPtAmount); await tx1.wait(); console.log("Tx", tx1.hash); } @@ -349,10 +365,13 @@ task("ops:vault:swapUnderlyingForPerps") await tx2.wait(); console.log("Tx", tx2.hash); - console.log("Signer perp balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); + console.log( + "Signer perp balance", + hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals()), + ); console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), ); }); @@ -366,7 +385,7 @@ task("ops:vault:swapPerpsForUnderlying") const vault = await hre.ethers.getContractAt("RolloverVault", vaultAddress); const perp = await hre.ethers.getContractAt("PerpetualTranche", await vault.perp()); const underlying = await hre.ethers.getContractAt("MockERC20", await vault.underlying()); - const fixedPtAmount = utils.parseUnits(perpAmount, await perp.decimals()); + const fixedPtAmount = hre.ethers.parseUnits(perpAmount, await perp.decimals()); const signer = (await hre.ethers.getSigners())[args.fromIdx]; const signerAddress = await signer.getAddress(); @@ -374,15 +393,18 @@ task("ops:vault:swapPerpsForUnderlying") console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + ); + console.log( + "Signer perp balance", + hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals()), ); - console.log("Signer perp balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); console.log("---------------------------------------------------------------"); console.log("Execution:"); console.log("Approving router to spend tokens:"); - if ((await perp.allowance(signerAddress, vault.address)).lt(fixedPtAmount)) { - const tx1 = await perp.connect(signer).approve(vault.address, fixedPtAmount); + if ((await perp.allowance(signerAddress, vault.target)).lt(fixedPtAmount)) { + const tx1 = await perp.connect(signer).approve(vault.target, fixedPtAmount); await tx1.wait(); console.log("Tx", tx1.hash); } @@ -394,7 +416,10 @@ task("ops:vault:swapPerpsForUnderlying") console.log( "Signer underlying balance", - utils.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + hre.ethers.formatUnits(await underlying.balanceOf(signerAddress), await underlying.decimals()), + ); + console.log( + "Signer perp balance", + hre.ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals()), ); - console.log("Signer perp balance", utils.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals())); }); diff --git a/spot-contracts/test/BondIssuer.ts b/spot-contracts/test/BondIssuer.ts index f27497b1..5d4fbcba 100644 --- a/spot-contracts/test/BondIssuer.ts +++ b/spot-contracts/test/BondIssuer.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import { ethers, network, upgrades } from "hardhat"; import { Contract, Transaction, Signer } from "ethers"; -import { TimeHelpers, setupBondFactory, bondAt } from "./helpers"; +import { TimeHelpers, setupBondFactory, bondAt, setupCollateralToken } from "./helpers"; const START_TIME = 2499998400; const mockTime = (x: number) => START_TIME + x; @@ -13,14 +13,14 @@ describe("BondIssuer", function () { const accounts = await ethers.getSigners(); deployer = accounts[0]; otherUser = accounts[1]; + bondFactory = await setupBondFactory(); - const Token = await ethers.getContractFactory("MockERC20"); - token = await Token.deploy(); - await token.init("Test token", "TEST"); + ({ collateralToken: token } = await setupCollateralToken("Test token", "TEST")); + const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, token.address, 86400, [200, 300, 500], 3600, 900], + [bondFactory.target, token.target, 86400, [200, 300, 500], 3600, 900], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, @@ -29,17 +29,17 @@ describe("BondIssuer", function () { }); afterEach(async function () { - await network.provider.send("hardhat_reset"); + await network.provider.request({ method: "hardhat_reset" }); }); describe("#setup", function () { it("should set storage parameters", async function () { expect(await issuer.owner()).to.eq(await deployer.getAddress()); - expect(await issuer.bondFactory()).to.eq(bondFactory.address); + expect(await issuer.bondFactory()).to.eq(bondFactory.target); expect(await issuer.minIssueTimeIntervalSec()).to.eq(3600); expect(await issuer.issueWindowOffsetSec()).to.eq(900); expect(await issuer.maxMaturityDuration()).to.eq(86400); - expect(await issuer.collateral()).to.eq(token.address); + expect(await issuer.collateral()).to.eq(token.target); expect(await issuer.trancheRatios(0)).to.eq(200); expect(await issuer.trancheRatios(1)).to.eq(300); expect(await issuer.trancheRatios(2)).to.eq(500); @@ -117,12 +117,12 @@ describe("BondIssuer", function () { await TimeHelpers.setNextBlockTimestamp(mockTime(901)); const tx = await issuer.issue(); const txR = await tx.wait(); - const bondIssuedEvent = txR.events[txR.events.length - 1]; - const bond = bondIssuedEvent.args.bond; + const bondIssuedLog = txR.logs[txR.logs.length - 1]; + const bond = bondIssuedLog.args.bond; expect(tx).to.emit(issuer, "BondIssued"); expect(await issuer.isInstance(bond)).to.eq(true); - expect(await issuer.callStatic.getLatestBond()).to.eq(bond); + expect(await issuer.getLatestBond.staticCall()).to.eq(bond); expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900)); expect(await issuer.issuedCount()).to.eq(1); @@ -204,7 +204,7 @@ describe("BondIssuer", function () { describe("#getLatestBond", function () { describe("when a new bond is up to be issued", function () { it("should issue a new bond and return the new bond", async function () { - const bond = await issuer.callStatic.getLatestBond(); + const bond = await issuer.getLatestBond.staticCall(); await expect(issuer.getLatestBond()).to.emit(issuer, "BondIssued").withArgs(bond); }); }); @@ -213,9 +213,9 @@ describe("BondIssuer", function () { it("should return the last bond", async function () { const tx = await issuer.issue(); const txR = await tx.wait(); - const bondIssuedEvent = txR.events[txR.events.length - 1]; - const bond = bondIssuedEvent.args.bond; - expect(await issuer.callStatic.getLatestBond()).to.eq(bond); + const bondIssuedLog = txR.logs[txR.logs.length - 1]; + const bond = bondIssuedLog.args.bond; + expect(await issuer.getLatestBond.staticCall()).to.eq(bond); await expect(issuer.getLatestBond()).to.not.emit(issuer, "BondIssued"); }); }); @@ -239,23 +239,23 @@ describe("BondIssuer", function () { beforeEach(async function () { await TimeHelpers.setNextBlockTimestamp(mockTime(900)); await issuer.issue(); - lastBond = await bondAt(await issuer.callStatic.getLatestBond()); + lastBond = await bondAt(await issuer.getLatestBond.staticCall()); expect(await issuer.issuedCount()).to.eq(1); - expect(await issuer.issuedBondAt(0)).to.eq(lastBond.address); + expect(await issuer.issuedBondAt(0)).to.eq(lastBond.target); expect(await issuer.activeCount()).to.eq(1); - expect(await issuer.activeBondAt(0)).to.eq(lastBond.address); + expect(await issuer.activeBondAt(0)).to.eq(lastBond.target); await TimeHelpers.setNextBlockTimestamp(mockTime(87301)); tx = issuer.matureActive(); await tx; }); it("should emit mature", async function () { - await expect(tx).to.emit(issuer, "BondMature").withArgs(lastBond.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(lastBond.target); await expect(tx).to.emit(lastBond, "Mature"); }); it("should keep track of active and mature bonds", async function () { expect(await issuer.issuedCount()).to.eq(1); - expect(await issuer.issuedBondAt(0)).to.eq(lastBond.address); + expect(await issuer.issuedBondAt(0)).to.eq(lastBond.target); expect(await issuer.activeCount()).to.eq(0); await expect(issuer.activeBondAt(0)).to.be.reverted; }); @@ -266,9 +266,9 @@ describe("BondIssuer", function () { beforeEach(async function () { await TimeHelpers.setNextBlockTimestamp(mockTime(900)); await issuer.issue(); - lastBond = await bondAt(await issuer.callStatic.getLatestBond()); + lastBond = await bondAt(await issuer.getLatestBond.staticCall()); expect(await issuer.issuedCount()).to.eq(1); - expect(await issuer.issuedBondAt(0)).to.eq(lastBond.address); + expect(await issuer.issuedBondAt(0)).to.eq(lastBond.target); await TimeHelpers.setNextBlockTimestamp(mockTime(87301)); await lastBond.mature(); @@ -281,7 +281,7 @@ describe("BondIssuer", function () { }); it("should keep track of active and mature bonds", async function () { expect(await issuer.issuedCount()).to.eq(1); - expect(await issuer.issuedBondAt(0)).to.eq(lastBond.address); + expect(await issuer.issuedBondAt(0)).to.eq(lastBond.target); expect(await issuer.activeCount()).to.eq(0); await expect(issuer.activeBondAt(0)).to.be.reverted; }); @@ -292,41 +292,41 @@ describe("BondIssuer", function () { beforeEach(async function () { await TimeHelpers.setNextBlockTimestamp(mockTime(900)); await issuer.issue(); - b1 = await bondAt(await issuer.callStatic.getLatestBond()); + b1 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(83700)); await issuer.issue(); - b2 = await bondAt(await issuer.callStatic.getLatestBond()); + b2 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(87300)); await issuer.issue(); - b3 = await bondAt(await issuer.callStatic.getLatestBond()); + b3 = await bondAt(await issuer.getLatestBond.staticCall()); expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(3); - expect(await issuer.activeBondAt(0)).to.eq(b1.address); - expect(await issuer.activeBondAt(1)).to.eq(b2.address); - expect(await issuer.activeBondAt(2)).to.eq(b3.address); + expect(await issuer.activeBondAt(0)).to.eq(b1.target); + expect(await issuer.activeBondAt(1)).to.eq(b2.target); + expect(await issuer.activeBondAt(2)).to.eq(b3.target); tx = issuer.matureActive(); await tx; }); it("should emit mature on the oldest bond", async function () { await expect(tx).to.emit(b1, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.target); }); it("should keep track of active and mature bonds", async function () { expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(2); - expect(await issuer.activeBondAt(0)).to.eq(b3.address); - expect(await issuer.activeBondAt(1)).to.eq(b2.address); + expect(await issuer.activeBondAt(0)).to.eq(b3.target); + expect(await issuer.activeBondAt(1)).to.eq(b2.target); await expect(issuer.activeBondAt(2)).to.be.reverted; }); }); @@ -336,44 +336,44 @@ describe("BondIssuer", function () { beforeEach(async function () { await TimeHelpers.setNextBlockTimestamp(mockTime(900)); await issuer.issue(); - b1 = await bondAt(await issuer.callStatic.getLatestBond()); + b1 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(83700)); await issuer.issue(); - b2 = await bondAt(await issuer.callStatic.getLatestBond()); + b2 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(87300)); await issuer.issue(); - b3 = await bondAt(await issuer.callStatic.getLatestBond()); + b3 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(170100)); expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(3); - expect(await issuer.activeBondAt(0)).to.eq(b1.address); - expect(await issuer.activeBondAt(1)).to.eq(b2.address); - expect(await issuer.activeBondAt(2)).to.eq(b3.address); + expect(await issuer.activeBondAt(0)).to.eq(b1.target); + expect(await issuer.activeBondAt(1)).to.eq(b2.target); + expect(await issuer.activeBondAt(2)).to.eq(b3.target); tx = issuer.matureActive(); await tx; }); it("should emit mature", async function () { await expect(tx).to.emit(b1, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.target); await expect(tx).to.emit(b2, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b2.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b2.target); }); it("should keep track of active and mature bonds", async function () { expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(1); - expect(await issuer.activeBondAt(0)).to.eq(b3.address); + expect(await issuer.activeBondAt(0)).to.eq(b3.target); await expect(issuer.activeBondAt(1)).to.be.reverted; }); }); @@ -383,44 +383,44 @@ describe("BondIssuer", function () { beforeEach(async function () { await TimeHelpers.setNextBlockTimestamp(mockTime(900)); await issuer.issue(); - b1 = await bondAt(await issuer.callStatic.getLatestBond()); + b1 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(83700)); await issuer.issue(); - b2 = await bondAt(await issuer.callStatic.getLatestBond()); + b2 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(87300)); await issuer.issue(); - b3 = await bondAt(await issuer.callStatic.getLatestBond()); + b3 = await bondAt(await issuer.getLatestBond.staticCall()); await TimeHelpers.setNextBlockTimestamp(mockTime(260100)); expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(3); - expect(await issuer.activeBondAt(0)).to.eq(b1.address); - expect(await issuer.activeBondAt(1)).to.eq(b2.address); - expect(await issuer.activeBondAt(2)).to.eq(b3.address); + expect(await issuer.activeBondAt(0)).to.eq(b1.target); + expect(await issuer.activeBondAt(1)).to.eq(b2.target); + expect(await issuer.activeBondAt(2)).to.eq(b3.target); tx = issuer.matureActive(); await tx; }); it("should emit mature", async function () { await expect(tx).to.emit(b1, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b1.target); await expect(tx).to.emit(b2, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b2.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b2.target); await expect(tx).to.emit(b3, "Mature"); - await expect(tx).to.emit(issuer, "BondMature").withArgs(b3.address); + await expect(tx).to.emit(issuer, "BondMature").withArgs(b3.target); }); it("should keep track of active and mature bonds", async function () { expect(await issuer.issuedCount()).to.eq(3); - expect(await issuer.issuedBondAt(0)).to.eq(b1.address); - expect(await issuer.issuedBondAt(1)).to.eq(b2.address); - expect(await issuer.issuedBondAt(2)).to.eq(b3.address); + expect(await issuer.issuedBondAt(0)).to.eq(b1.target); + expect(await issuer.issuedBondAt(1)).to.eq(b2.target); + expect(await issuer.issuedBondAt(2)).to.eq(b3.target); expect(await issuer.activeCount()).to.eq(0); await expect(issuer.activeBondAt(0)).to.be.reverted; }); diff --git a/spot-contracts/test/FeePolicy.ts b/spot-contracts/test/FeePolicy.ts index b3eea137..3fa6930d 100644 --- a/spot-contracts/test/FeePolicy.ts +++ b/spot-contracts/test/FeePolicy.ts @@ -1,14 +1,22 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { ethers, upgrades } from "hardhat"; import { Contract, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { toPercFixedPtAmt, toFixedPtAmt } from "./helpers"; -use(smock.matchers); let feePolicy: Contract, deployer: Signer, otherUser: Signer; const toPerc = toPercFixedPtAmt; const toAmt = toFixedPtAmt; +const toLine = (x1: string, y1: string, x2: string, y2: string) => ({ + x1: toPerc(x1), + y1: toPerc(y1), + x2: toPerc(x2), + y2: toPerc(y2), +}); +const toRange = (lower: string, upper: string) => ({ + lower: toPerc(lower), + upper: toPerc(upper), +}); describe("FeePolicy", function () { beforeEach(async function () { @@ -24,9 +32,38 @@ describe("FeePolicy", function () { describe("#init", function () { it("should return the initial parameters", async function () { - expect(await feePolicy.targetSubscriptionRatio()).to.eq(toPerc("1.33")); - expect(await feePolicy.deviationRatioBoundLower()).to.eq(toPerc("0.75")); - expect(await feePolicy.deviationRatioBoundUpper()).to.eq(toPerc("2")); + expect(await feePolicy.targetSubscriptionRatio()).to.eq(toPerc("1.5")); + + const f1 = await feePolicy.feeFnDRDown(); + expect(f1[0]).to.eq(toPerc("0.66")); + expect(f1[1]).to.eq(toPerc("0.25")); + expect(f1[2]).to.eq(toPerc("0.95")); + expect(f1[3]).to.eq(toPerc("0")); + + const f2 = await feePolicy.feeFnDRUp(); + expect(f2[0]).to.eq(toPerc("1.05")); + expect(f2[1]).to.eq(toPerc("0")); + expect(f2[2]).to.eq(toPerc("1.5")); + expect(f2[3]).to.eq(toPerc("0.25")); + + const drEq = await feePolicy.equilibriumDR(); + expect(drEq[0]).to.eq(toPerc("0.95")); + expect(drEq[1]).to.eq(toPerc("1.05")); + + expect(await feePolicy.perpDebasementLag()).to.eq(30); + expect(await feePolicy.perpEnrichmentLag()).to.eq(30); + + const l1 = await feePolicy.perpDebasementPercLimits(); + expect(l1[0]).to.eq(toPerc("0.005")); + expect(l1[1]).to.eq(toPerc("0.025")); + + const l2 = await feePolicy.perpEnrichmentPercLimits(); + expect(l2[0]).to.eq(toPerc("0.005")); + expect(l2[1]).to.eq(toPerc("0.025")); + + expect(await feePolicy.rebalanceFreqSec()).to.eq(86400); + expect(await feePolicy.protocolSharePerc()).to.eq(toPerc("0.01")); + expect(await feePolicy.protocolFeeCollector()).to.eq(await deployer.getAddress()); }); it("should return owner", async function () { expect(await feePolicy.owner()).to.eq(await deployer.getAddress()); @@ -45,497 +82,457 @@ describe("FeePolicy", function () { }); }); - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updateTargetSubscriptionRatio(toPerc("0.5")), - ).to.be.revertedWithCustomError(feePolicy, "InvalidTargetSRBounds"); - }); - }); - - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updateTargetSubscriptionRatio(toPerc("2.1")), - ).to.be.revertedWithCustomError(feePolicy, "InvalidTargetSRBounds"); - }); - }); - describe("when triggered by owner", function () { it("should update the target sr", async function () { - expect(await feePolicy.targetSubscriptionRatio()).to.eq(toPerc("1.33")); + expect(await feePolicy.targetSubscriptionRatio()).to.eq(toPerc("1.5")); await feePolicy.connect(deployer).updateTargetSubscriptionRatio(toPerc("1.25")); expect(await feePolicy.targetSubscriptionRatio()).to.eq(toPerc("1.25")); }); }); }); - describe("#updateDeviationRatioBounds", function () { + describe("#updateEquilibriumDR", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { await expect( - feePolicy.connect(otherUser).updateDeviationRatioBounds(toPerc("1"), toPerc("1")), + feePolicy.connect(otherUser).updateEquilibriumDR([toPerc("0.9"), toPerc("1.1")]), ).to.be.revertedWith("Ownable: caller is not the owner"); }); }); - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updateDeviationRatioBounds(toPerc("1.01"), toPerc("2")), - ).to.be.revertedWithCustomError(feePolicy, "InvalidDRBounds"); - }); - }); - - describe("when parameters are invalid", function () { + describe("when range is invalid", function () { it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updateDeviationRatioBounds(toPerc("0.5"), toPerc("0.99")), - ).to.be.revertedWithCustomError(feePolicy, "InvalidDRBounds"); + await expect(feePolicy.updateEquilibriumDR([toPerc("1.2"), toPerc("1.1")])).to.be.revertedWithCustomError( + feePolicy, + "InvalidRange", + ); + await expect(feePolicy.updateEquilibriumDR([toPerc("1.01"), toPerc("1.1")])).to.be.revertedWithCustomError( + feePolicy, + "InvalidRange", + ); + await expect(feePolicy.updateEquilibriumDR([toPerc("0.9"), toPerc("0.99")])).to.be.revertedWithCustomError( + feePolicy, + "InvalidRange", + ); }); }); describe("when triggered by owner", function () { it("should update the target sr", async function () { - expect(await feePolicy.deviationRatioBoundLower()).to.eq(toPerc("0.75")); - expect(await feePolicy.deviationRatioBoundUpper()).to.eq(toPerc("2")); - await feePolicy.connect(deployer).updateDeviationRatioBounds(toPerc("0.5"), toPerc("1.5")); - expect(await feePolicy.deviationRatioBoundLower()).to.eq(toPerc("0.5")); - expect(await feePolicy.deviationRatioBoundUpper()).to.eq(toPerc("1.5")); + await feePolicy.connect(deployer).updateEquilibriumDR([toPerc("0.9"), toPerc("1.1")]); + const eq = await feePolicy.equilibriumDR(); + expect(eq[0]).to.eq(toPerc("0.9")); + expect(eq[1]).to.eq(toPerc("1.1")); }); }); }); - describe("#updatePerpMintFees", function () { + describe("#updateFees", function () { + const VALID_DOWN = toLine("0.0", "1.0", "0.99", "0.0"); + const VALID_UP = toLine("1.01", "0.0", "2.0", "1.0"); + describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(feePolicy.connect(otherUser).updatePerpMintFees(toPerc("0.01"))).to.be.revertedWith( + await expect(feePolicy.connect(otherUser).updateFees(VALID_DOWN, VALID_UP)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); }); - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect(feePolicy.connect(deployer).updatePerpMintFees(toPerc("1.01"))).to.be.revertedWithCustomError( + describe("when parameters are invalid (InvalidFees)", function () { + it("x1 > x2 for downwards leg", async function () { + const badDown = toLine("1.1", "1.0", "1.0", "0.0"); + await expect(feePolicy.connect(deployer).updateFees(badDown, VALID_UP)).to.be.revertedWithCustomError( feePolicy, - "InvalidPerc", + "InvalidFees", ); }); - }); - describe("when triggered by owner", function () { - it("should update the mint fees", async function () { - expect(await feePolicy.computePerpMintFeePerc()).to.eq("0"); - await feePolicy.connect(deployer).updatePerpMintFees(toPerc("0.01")); - expect(await feePolicy.computePerpMintFeePerc()).to.eq(toPerc("0.01")); - }); - }); - }); - - describe("#updatePerpBurnFees", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - await expect(feePolicy.connect(otherUser).updatePerpBurnFees(toPerc("0.01"))).to.be.revertedWith( - "Ownable: caller is not the owner", + it("equilibrium zone crosses 1.0", async function () { + const badDown = toLine("0.0", "1.0", "1.1", "0.0"); + await expect(feePolicy.connect(deployer).updateFees(badDown, VALID_UP)).to.be.revertedWithCustomError( + feePolicy, + "InvalidFees", ); - }); - }); - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect(feePolicy.connect(deployer).updatePerpBurnFees(toPerc("1.01"))).to.be.revertedWithCustomError( + const badUp = toLine("0.9", "0.0", "2.0", "1.0"); + await expect(feePolicy.connect(deployer).updateFees(VALID_DOWN, badUp)).to.be.revertedWithCustomError( feePolicy, - "InvalidPerc", + "InvalidFees", ); }); - }); - describe("when triggered by owner", function () { - it("should update the burn fees", async function () { - expect(await feePolicy.computePerpBurnFeePerc()).to.eq("0"); - await feePolicy.connect(deployer).updatePerpBurnFees(toPerc("0.01")); - expect(await feePolicy.computePerpBurnFeePerc()).to.eq(toPerc("0.01")); - }); - }); - }); + it("fees not monotonic wrt distance from 1.0", async function () { + const badDown = toLine("0.0", "0.0", "1.0", "1.0"); + await expect(feePolicy.connect(deployer).updateFees(badDown, VALID_UP)).to.be.revertedWithCustomError( + feePolicy, + "InvalidFees", + ); - describe("#updatePerpRolloverFees", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(otherUser).updatePerpRolloverFees({ - lower: toPerc("-0.01"), - upper: toPerc("0.01"), - growth: toPerc("3"), - }), - ).to.be.revertedWith("Ownable: caller is not the owner"); + const badUp = toLine("1.0", "1.0", "2.0", "0.5"); + await expect(feePolicy.connect(deployer).updateFees(VALID_DOWN, badUp)).to.be.revertedWithCustomError( + feePolicy, + "InvalidFees", + ); }); - }); - describe("when parameters are invalid", function () { - it("should revert", async function () { + it("fee percentage > 1 (100 %)", async function () { await expect( - feePolicy.connect(deployer).updatePerpRolloverFees({ - lower: toPerc("-0.051"), - upper: toPerc("0.01"), - growth: toPerc("3"), - }), - ).to.be.revertedWithCustomError(feePolicy, "InvalidSigmoidAsymptotes"); - }); - it("should revert", async function () { + feePolicy.connect(deployer).updateFees(toLine("0.0", "1.1", "1.0", "0.1"), VALID_UP), + ).to.be.revertedWithCustomError(feePolicy, "InvalidFees"); await expect( - feePolicy.connect(deployer).updatePerpRolloverFees({ - lower: toPerc("-0.01"), - upper: toPerc("0.051"), - growth: toPerc("3"), - }), - ).to.be.revertedWithCustomError(feePolicy, "InvalidSigmoidAsymptotes"); - }); - - it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updatePerpRolloverFees({ - lower: toPerc("0.02"), - upper: toPerc("0.01"), - growth: toPerc("3"), - }), - ).to.be.revertedWithCustomError(feePolicy, "InvalidSigmoidAsymptotes"); + feePolicy.connect(deployer).updateFees(VALID_DOWN, toLine("1.0", "0", "2.0", "1.1")), + ).to.be.revertedWithCustomError(feePolicy, "InvalidFees"); }); }); - describe("when triggered by owner", function () { - it("should update parameters", async function () { - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1"))).to.eq(0); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("10"))).to.eq(toPerc("0.00769230")); - expect(await feePolicy.computePerpRolloverFeePerc("0")).to.eq(toPerc("-0.00245837")); - - await feePolicy.connect(deployer).updatePerpRolloverFees({ - lower: toPerc("-0.009"), - upper: toPerc("0.009"), - growth: toPerc("3"), - }); - - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1"))).to.eq(0); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("10"))).to.eq(toPerc("0.009")); - expect(await feePolicy.computePerpRolloverFeePerc("0")).to.eq(toPerc("-0.007")); + describe("when triggered by owner with valid parameters", function () { + it("should update the fee functions", async function () { + await feePolicy.connect(deployer).updateFees(VALID_DOWN, VALID_UP); + const f1 = await feePolicy.feeFnDRDown(); + expect(f1.x1).to.eq(VALID_DOWN.x1); + expect(f1.y1).to.eq(VALID_DOWN.y1); + expect(f1.x2).to.eq(VALID_DOWN.x2); + expect(f1.y2).to.eq(VALID_DOWN.y2); + const f2 = await feePolicy.feeFnDRUp(); + expect(f2.x1).to.eq(VALID_UP.x1); + expect(f2.y1).to.eq(VALID_UP.y1); + expect(f2.x2).to.eq(VALID_UP.x2); + expect(f2.y2).to.eq(VALID_UP.y2); }); }); }); - describe("#updateVaultMintFees", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - await expect(feePolicy.connect(otherUser).updateVaultMintFees(toPerc("0.01"))).to.be.revertedWith( - "Ownable: caller is not the owner", - ); - }); - }); - - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect(feePolicy.connect(deployer).updateVaultMintFees(toPerc("1.01"))).to.be.revertedWithCustomError( - feePolicy, - "InvalidPerc", - ); - }); - }); - - describe("when triggered by owner", function () { - beforeEach(async function () {}); - it("should update the vault mint fees", async function () { - expect(await feePolicy.computeVaultMintFeePerc()).to.eq("0"); - await feePolicy.connect(deployer).updateVaultMintFees(toPerc("0.025")); - expect(await feePolicy.computeVaultMintFeePerc()).to.eq(toPerc("0.025")); - }); - }); - }); + describe("#updateRebalanceConfig", function () { + const DEBASE_LAG = 30; + const ENRICH_LAG = 30; + const DEBASE_RNG = toRange("0.01", "0.05"); + const ENRICH_RNG = toRange("0.01", "0.03"); + const REBAL_FREQ = 86_400; - describe("#updateVaultBurnFees", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(feePolicy.connect(otherUser).updateVaultBurnFees(toPerc("0.01"))).to.be.revertedWith( - "Ownable: caller is not the owner", - ); + await expect( + feePolicy + .connect(otherUser) + .updateRebalanceConfig(DEBASE_LAG, ENRICH_LAG, DEBASE_RNG, ENRICH_RNG, REBAL_FREQ), + ).to.be.revertedWith("Ownable: caller is not the owner"); }); }); - describe("when parameters are invalid", function () { + describe("when range is invalid", function () { it("should revert", async function () { - await expect(feePolicy.connect(deployer).updateVaultBurnFees(toPerc("1.01"))).to.be.revertedWithCustomError( - feePolicy, - "InvalidPerc", - ); + await expect( + feePolicy + .connect(deployer) + .updateRebalanceConfig(DEBASE_LAG, ENRICH_LAG, toRange("0.06", "0.05"), ENRICH_RNG, REBAL_FREQ), + ).to.be.revertedWithCustomError(feePolicy, "InvalidRange"); + await expect( + feePolicy + .connect(deployer) + .updateRebalanceConfig(DEBASE_LAG, ENRICH_LAG, DEBASE_RNG, toRange("0.06", "0.05"), REBAL_FREQ), + ).to.be.revertedWithCustomError(feePolicy, "InvalidRange"); }); }); describe("when triggered by owner", function () { - it("should update the vault burn fees", async function () { - expect(await feePolicy.computeVaultBurnFeePerc()).to.eq("0"); - await feePolicy.connect(deployer).updateVaultBurnFees(toPerc("0.025")); - expect(await feePolicy.computeVaultBurnFeePerc()).to.eq(toPerc("0.025")); + it("should update every field", async function () { + await feePolicy + .connect(deployer) + .updateRebalanceConfig(DEBASE_LAG, ENRICH_LAG, DEBASE_RNG, ENRICH_RNG, REBAL_FREQ); + + const newDebaseLag = await feePolicy.perpDebasementLag(); + const newEnrichLag = await feePolicy.perpEnrichmentLag(); + const newDebaseRng = await feePolicy.perpDebasementPercLimits(); + const newEnrichRng = await feePolicy.perpEnrichmentPercLimits(); + const newFreq = await feePolicy.rebalanceFreqSec(); + + expect(newDebaseLag).to.equal(DEBASE_LAG); + expect(newEnrichLag).to.equal(ENRICH_LAG); + expect(newDebaseRng.lower).to.equal(DEBASE_RNG.lower); + expect(newDebaseRng.upper).to.equal(DEBASE_RNG.upper); + expect(newEnrichRng.lower).to.equal(ENRICH_RNG.lower); + expect(newEnrichRng.upper).to.equal(ENRICH_RNG.upper); + expect(newFreq).to.equal(REBAL_FREQ); }); }); }); - describe("#updateVaultUnderlyingToPerpSwapFeePerc", function () { + describe("#updateProtocolFeeConfig", function () { + const VALID_SHARE = toPerc("0.05"); + const OVER_SHARE = toPerc("1.01"); + describe("when triggered by non-owner", function () { it("should revert", async function () { await expect( - feePolicy.connect(otherUser).updateVaultUnderlyingToPerpSwapFeePerc(toPerc("0.1")), + feePolicy.connect(otherUser).updateProtocolFeeConfig(VALID_SHARE, await otherUser.getAddress()), ).to.be.revertedWith("Ownable: caller is not the owner"); }); }); - describe("when parameters are invalid", function () { - it("should revert", async function () { + describe("when percentage is > 100 %", function () { + it("should revert with InvalidPerc", async function () { await expect( - feePolicy.connect(deployer).updateVaultUnderlyingToPerpSwapFeePerc(toPerc("1.01")), + feePolicy.connect(deployer).updateProtocolFeeConfig(OVER_SHARE, await otherUser.getAddress()), ).to.be.revertedWithCustomError(feePolicy, "InvalidPerc"); }); }); - describe("when triggered by owner", function () { - it("should update the vault burn fees", async function () { - expect(await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(toPerc("1.01"), toPerc("1.01"))).to.eq( - toPerc("1"), - ); - await feePolicy.connect(deployer).updateVaultUnderlyingToPerpSwapFeePerc(toPerc("0.1")); - expect(await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(toPerc("1.01"), toPerc("1.01"))).to.eq( - toPerc("0.1"), - ); + describe("when called by owner with valid params", function () { + it("should update both fields", async function () { + await feePolicy.connect(deployer).updateProtocolFeeConfig(VALID_SHARE, await otherUser.getAddress()); + expect(await feePolicy.protocolSharePerc()).to.eq(VALID_SHARE); + expect(await feePolicy.protocolFeeCollector()).to.eq(await otherUser.getAddress()); }); }); }); - describe("#updateVaultPerpToUnderlyingSwapFeePerc", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(otherUser).updateVaultPerpToUnderlyingSwapFeePerc(toPerc("0.1")), - ).to.be.revertedWith("Ownable: caller is not the owner"); - }); + describe("fee logic", function () { + beforeEach(async function () { + await feePolicy.updateFees(toLine("0.66", "0.5", "0.99", "0"), toLine("1.01", "0.01", "1.5", "0.5")); }); - describe("when parameters are invalid", function () { - it("should revert", async function () { - await expect( - feePolicy.connect(deployer).updateVaultPerpToUnderlyingSwapFeePerc(toPerc("1.01")), - ).to.be.revertedWithCustomError(feePolicy, "InvalidPerc"); + async function cmpFees(dr1, dr2, fees) { + expect(await feePolicy.computeFeePerc(toPerc(dr1), toPerc(dr2))).to.eq(toPerc(fees)); + } + + describe("when dr is decreasing", function () { + it("should compute fees as expected", async function () { + await cmpFees("1.1", "1.01", "0"); + await cmpFees("1.01", "1", "0"); + await cmpFees("1.05", "0.95", "0.01212121"); + await cmpFees("1.01", "0.96", "0.01363636"); + await cmpFees("1.1", "0.99", "0"); + await cmpFees("0.99", "0.95", "0.03030304"); + await cmpFees("0.9", "0.8", "0.21212122"); + await cmpFees("1.2", "0.8", "0.06837121"); + await cmpFees("0.8", "0.75", "0.32575758"); }); }); - describe("when triggered by owner", function () { - it("should update the vault burn fees", async function () { - expect(await feePolicy.computePerpToUnderlyingVaultSwapFeePerc(toPerc("1"), toPerc("1"))).to.eq(toPerc("1")); - await feePolicy.connect(deployer).updateVaultPerpToUnderlyingSwapFeePerc(toPerc("0.2")); - expect(await feePolicy.computePerpToUnderlyingVaultSwapFeePerc(toPerc("1"), toPerc("1"))).to.eq(toPerc("0.2")); + describe("when dr is increasing", function () { + it("should compute fees as expected", async function () { + await cmpFees("0.8", "0.8", "0.01"); + await cmpFees("0.9", "0.99", "0.01"); + await cmpFees("0.9", "1", "0.01"); + await cmpFees("0.95", "1.05", "0.018"); + await cmpFees("0.99", "1.04", "0.019"); + await cmpFees("0.99", "1.1", "0.04681818"); + await cmpFees("1.01", "1.05", "0.03"); + await cmpFees("1.01", "1.25", "0.13"); + await cmpFees("1.25", "1.35", "0.3"); }); }); }); - describe("fee logic", function () { + describe("#computeDeviationRatio", async function () { beforeEach(async function () { - await feePolicy.updatePerpMintFees(toPerc("0.025")); - await feePolicy.updatePerpBurnFees(toPerc("0.035")); - await feePolicy.updatePerpRolloverFees({ - lower: toPerc("-0.00253"), - upper: toPerc("0.00769"), - growth: toPerc("5"), - }); - await feePolicy.updateVaultUnderlyingToPerpSwapFeePerc(toPerc("0.1")); - await feePolicy.updateVaultPerpToUnderlyingSwapFeePerc(toPerc("0.15")); - await feePolicy.updateVaultMintFees(toPerc("0.05")); - await feePolicy.updateVaultBurnFees(toPerc("0.075")); - await feePolicy.updateDeviationRatioBounds(toPerc("0.85"), toPerc("1.15")); + await feePolicy.updateTargetSubscriptionRatio(toPerc("1.25")); }); - describe("when dr is decreasing", function () { - async function cmpFees(dr1, dr2, fees) { - // perp mint, vault burn and swap u2p - expect(await feePolicy.computePerpMintFeePerc()).to.eq(toPerc(fees[0])); - expect(await feePolicy.computeVaultBurnFeePerc()).to.eq(toPerc(fees[1])); - expect(await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(toPerc(dr1), toPerc(dr2))).to.eq( - toPerc(fees[2]), - ); - } - - describe("when ONE < dr2, dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.1", "1.01", ["0.025", "0.075", "0.1"]); - }); - }); - - describe("when ONE <= dr2, dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.01", "1", ["0.025", "0.075", "0.1"]); + describe("when deviation = 1.0", function () { + it("should return 1", async function () { + const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("500"), + seniorTR: 200, }); + expect(r).to.eq(toPerc("1")); }); + }); - describe("when dr2 < ONE < dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.05", "0.95", ["0.025", "0.075", "0.1"]); + describe("when deviation > 1.0", function () { + it("should compute dr", async function () { + const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toPerc("2")); }); + }); - describe("when dr2 < ONE < dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.01", "0.96", ["0.025", "0.075", "0.1"]); + describe("when deviation < 1.0", function () { + it("should compute dr", async function () { + const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("250"), + seniorTR: 200, }); + expect(r).to.eq(toPerc("0.5")); }); + }); + }); - describe("when dr2 < ONE < dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.1", "0.99", ["0.025", "0.075", "0.1"]); - }); - }); + describe("#computeDRNormSeniorTR", function () { + it("should compute the dr norm ratio", async function () { + await feePolicy.updateTargetSubscriptionRatio(toPerc("2")); + expect(await feePolicy.computeDRNormSeniorTR(200)).to.eq(toPerc("0.11111111")); + expect(await feePolicy.computeDRNormSeniorTR(500)).to.eq(toPerc("0.33333333")); + expect(await feePolicy.computeDRNormSeniorTR(333)).to.eq(toPerc("0.19976004")); + expect(await feePolicy.computeDRNormSeniorTR(666)).to.eq(toPerc("0.49925037")); + expect(await feePolicy.computeDRNormSeniorTR(750)).to.eq(toPerc("0.6")); + }); + }); - describe("when dr2,dr1 < ONE", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.99", "0.95", ["0.025", "0.075", "0.1"]); - }); - }); + describe("#computeRebalanceAmount", async function () { + beforeEach(async function () { + await feePolicy.updateTargetSubscriptionRatio(toPerc("1.25")); + await feePolicy.connect(deployer).updateRebalanceConfig(1, 1, toRange("0", "10"), toRange("0", "10"), 86400); + }); - describe("when dr2 < lower < dr1 < ONE", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.9", "0.8", ["0.025", "0.075", "1"]); + describe("when deviation is within eq range", function () { + it("should compute rebalance data", async function () { + await feePolicy.updateEquilibriumDR([toPerc("0.5"), toPerc("2")]); + const r1 = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("120"), + vaultTVL: toAmt("500"), + seniorTR: 200, }); - }); - - describe("when dr2 < lower < ONE < dr1", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.2", "0.8", ["0.025", "0.075", "1"]); + expect(r1).to.eq(0n); + const r2 = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("80"), + vaultTVL: toAmt("500"), + seniorTR: 200, }); + expect(r2).to.eq(0n); }); + }); - describe("when dr2,dr1 < lower", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.8", "0.75", ["0.025", "0.075", "1"]); + describe("when deviation = 1.0", function () { + it("should compute rebalance data", async function () { + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("500"), + seniorTR: 200, }); + expect(r).to.eq(0n); }); }); - describe("when dr is increasing", function () { - async function cmpFees(dr1, dr2, fees) { - // perp burn, vault mint and swap p2u - expect(await feePolicy.computePerpBurnFeePerc()).to.eq(toPerc(fees[0])); - expect(await feePolicy.computeVaultMintFeePerc()).to.eq(toPerc(fees[1])); - expect(await feePolicy.computePerpToUnderlyingVaultSwapFeePerc(toPerc(dr1), toPerc(dr2))).to.eq( - toPerc(fees[2]), - ); - } - - describe("when dr1, dr2 < ONE", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.9", "0.99", ["0.035", "0.05", "0.15"]); + describe("when deviation ~= 1.0", function () { + it("should compute rebalance data", async function () { + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("500.001"), + seniorTR: 200, }); + expect(r).to.eq(0n); }); + }); - describe("when dr1, dr2 <= ONE", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.9", "1", ["0.035", "0.05", "0.15"]); + describe("when deviation ~= 1.0", function () { + it("should compute rebalance data", async function () { + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("99.999"), + vaultTVL: toAmt("500"), + seniorTR: 200, }); + expect(r).to.eq(0n); }); + }); - describe("when dr1 < ONE < dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.95", "1.05", ["0.035", "0.05", "0.15"]); + describe("enrichment", function () { + it("should compute rebalance data", async function () { + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("83.333326")); }); - describe("when dr1 < ONE < dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.99", "1.04", ["0.035", "0.05", "0.15"]); + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(1, 2, toRange("0", "10"), toRange("0", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("41.666663")); }); - describe("when dr1 < ONE < dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("0.99", "1.1", ["0.035", "0.05", "0.15"]); + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(1, 10, toRange("0", "10"), toRange("0.1", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("10")); }); - describe("when ONE < dr1, dr2 < upper", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.01", "1.05", ["0.035", "0.05", "0.15"]); + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(1, 10, toRange("0", "10"), toRange("0", "0.05"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("5")); }); - describe("when ONE < dr1 < upper < dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.01", "1.25", ["0.035", "0.05", "1"]); + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(1, 10, toRange("0", "10"), toRange("1", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("100"), + vaultTVL: toAmt("1000"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("83.333326")); }); + }); - describe("when dr1 < ONE < upper < dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.01", "1.25", ["0.035", "0.05", "1"]); + describe("debasement", function () { + it("should compute rebalance data", async function () { + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("1000"), + vaultTVL: toAmt("2500"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("-416.66669")); }); - describe("when upper < dr1, dr2", function () { - it("should compute fees as expected", async function () { - await cmpFees("1.25", "1.35", ["0.035", "0.05", "1"]); + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(2, 1, toRange("0", "10"), toRange("0", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("1000"), + vaultTVL: toAmt("2500"), + seniorTR: 200, }); + expect(r).to.eq(toAmt("-208.333345")); }); - }); - describe("rollover fee", function () { - it("should compute fees as expected", async function () { - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.01"))).to.eq(toPerc("-0.00242144")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.25"))).to.eq(toPerc("-0.00228606")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.5"))).to.eq(toPerc("-0.00196829")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.75"))).to.eq(toPerc("-0.00128809")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.9"))).to.eq(toPerc("-0.00060117")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("0.99"))).to.eq(toPerc("-0.00004101")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1"))).to.eq("0"); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.01"))).to.eq(toPerc("0.00004146")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.05"))).to.eq(toPerc("0.00034407")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.1"))).to.eq(toPerc("0.00071519")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.25"))).to.eq(toPerc("0.00195646")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.5"))).to.eq(toPerc("0.00411794")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("1.75"))).to.eq(toPerc("0.00580663")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("2"))).to.eq(toPerc("0.00680345")); - expect(await feePolicy.computePerpRolloverFeePerc(toPerc("5"))).to.eq(toPerc("0.00768997")); - }); - }); - }); - - describe("#computeDeviationRatio", async function () { - beforeEach(async function () { - await feePolicy.updateTargetSubscriptionRatio(toPerc("1.25")); - }); - - describe("when deviation = 1.0", function () { - it("should return 1", async function () { - const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ - perpTVL: toAmt("100"), - vaultTVL: toAmt("500"), + it("should compute rebalance data", async function () { + await feePolicy + .connect(deployer) + .updateRebalanceConfig(10, 1, toRange("0.05", "10"), toRange("0", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("1000"), + vaultTVL: toAmt("2500"), seniorTR: 200, }); - expect(r).to.eq(toPerc("1")); + expect(r).to.eq(toAmt("-50")); }); - }); - describe("when deviation > 1.0", function () { - it("should compute dr", async function () { - const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ - perpTVL: toAmt("100"), - vaultTVL: toAmt("1000"), + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(10, 1, toRange("0", "0.03"), toRange("0", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("1000"), + vaultTVL: toAmt("2500"), seniorTR: 200, }); - expect(r).to.eq(toPerc("2")); + expect(r).to.eq(toAmt("-30")); }); - }); - describe("when deviation < 1.0", function () { - it("should compute dr", async function () { - const r = await feePolicy["computeDeviationRatio((uint256,uint256,uint256))"]({ - perpTVL: toAmt("100"), - vaultTVL: toAmt("250"), + it("should compute rebalance data", async function () { + await feePolicy.connect(deployer).updateRebalanceConfig(10, 1, toRange("1", "10"), toRange("0", "10"), 86400); + const r = await feePolicy.computeRebalanceAmount({ + perpTVL: toAmt("1000"), + vaultTVL: toAmt("2500"), seniorTR: 200, }); - expect(r).to.eq(toPerc("0.5")); + expect(r).to.eq(toAmt("-416.66669")); }); }); }); diff --git a/spot-contracts/test/RouterV2.ts b/spot-contracts/test/RouterV2.ts index 040f3433..27374c59 100644 --- a/spot-contracts/test/RouterV2.ts +++ b/spot-contracts/test/RouterV2.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; -import { constants, Contract, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; +import { Contract, Signer } from "ethers"; import { setupCollateralToken, setupBondFactory, @@ -11,8 +10,9 @@ import { advancePerpQueue, advanceTime, mintCollteralToken, + DMock, + toPercFixedPtAmt, } from "./helpers"; -use(smock.matchers); let perp: Contract, bondFactory: Contract, @@ -40,21 +40,22 @@ describe("RouterV2", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.computePerpRolloverFeePerc.returns("0"); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -62,12 +63,19 @@ describe("RouterV2", function () { await perp.updateTolerableTrancheMaturity(600, 3600); await advancePerpQueue(perp, 3600); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await smock.fake(RolloverVault); - await vault.getTVL.returns("0"); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + vault = new DMock(RolloverVault); + await vault.deploy(); + await vault.mockMethod("getTVL()", [0]); + await perp.updateVault(vault.target); - depositBond = await bondAt(await perp.callStatic.getDepositBond()); + depositBond = await bondAt(await perp.getDepositBond.staticCall()); depositTranches = await getTranches(depositBond); const Router = await ethers.getContractFactory("RouterV2"); @@ -80,11 +88,11 @@ describe("RouterV2", function () { describe("#previewTranche", function () { it("should compute the tranche amounts", async function () { - const r = await router.callStatic.previewTranche(perp.address, toFixedPtAmt("1000")); - expect(r[0]).to.eq(await perp.callStatic.getDepositBond()); - expect(r[1][0].token).to.eq(depositTranches[0].address); + const r = await router.previewTranche.staticCall(perp.target, toFixedPtAmt("1000")); + expect(r[0]).to.eq(await perp.getDepositBond.staticCall()); + expect(r[1][0].token).to.eq(depositTranches[0].target); expect(r[1][0].amount).to.eq(toFixedPtAmt("200")); - expect(r[1][1].token).to.eq(depositTranches[1].address); + expect(r[1][1].token).to.eq(depositTranches[1].target); expect(r[1][1].amount).to.eq(toFixedPtAmt("800")); }); }); @@ -92,37 +100,37 @@ describe("RouterV2", function () { describe("#trancheAndDeposit", function () { beforeEach(async function () { await mintCollteralToken(collateralToken, toFixedPtAmt("1100"), deployer); - await collateralToken.transfer(router.address, toFixedPtAmt("100")); + await collateralToken.transfer(router.target, toFixedPtAmt("100")); }); describe("when deposit bond is incorrect", function () { beforeEach(async function () { - await collateralToken.approve(router.address, constants.MaxUint256); + await collateralToken.approve(router.target, ethers.MaxUint256); await advancePerpQueue(perp, 7200); }); it("should revert", async function () { await expect( - router.trancheAndDeposit(perp.address, depositBond.address, toFixedPtAmt("1000")), + router.trancheAndDeposit(perp.target, depositBond.target, toFixedPtAmt("1000")), ).to.revertedWithCustomError(perp, "UnexpectedAsset"); }); }); describe("when deposit bond is not issued", function () { beforeEach(async function () { - await collateralToken.approve(router.address, constants.MaxUint256); + await collateralToken.approve(router.target, ethers.MaxUint256); await advanceTime(7200); }); it("should not revert", async function () { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); - await expect(router.trancheAndDeposit(perp.address, depositBond.address, toFixedPtAmt("1000"))).not.to.be + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); + await expect(router.trancheAndDeposit(perp.target, depositBond.target, toFixedPtAmt("1000"))).not.to.be .reverted; }); }); describe("when deposit bond is correct", function () { beforeEach(async function () { - await collateralToken.approve(router.address, constants.MaxUint256); - await router.trancheAndDeposit(perp.address, depositBond.address, toFixedPtAmt("1000")); + await collateralToken.approve(router.target, ethers.MaxUint256); + await router.trancheAndDeposit(perp.target, depositBond.target, toFixedPtAmt("1000")); }); it("should mint tranches", async function () { @@ -139,10 +147,10 @@ describe("RouterV2", function () { }); it("should leave no dust", async function () { - expect(await depositTranches[0].balanceOf(router.address)).to.eq("0"); - expect(await depositTranches[1].balanceOf(router.address)).to.eq("0"); - expect(await perp.balanceOf(router.address)).to.eq("0"); - expect(await collateralToken.balanceOf(router.address)).to.eq("0"); + expect(await depositTranches[0].balanceOf(router.target)).to.eq("0"); + expect(await depositTranches[1].balanceOf(router.target)).to.eq("0"); + expect(await perp.balanceOf(router.target)).to.eq("0"); + expect(await collateralToken.balanceOf(router.target)).to.eq("0"); }); }); }); diff --git a/spot-contracts/test/_utils/HelpersTester.ts b/spot-contracts/test/_utils/HelpersTester.ts index 09cf7d7e..a428e892 100644 --- a/spot-contracts/test/_utils/HelpersTester.ts +++ b/spot-contracts/test/_utils/HelpersTester.ts @@ -1,8 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers } from "hardhat"; import { Contract, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; - import { TimeHelpers, setupCollateralToken, @@ -15,8 +13,8 @@ import { getTranches, getContractFactoryFromExternalArtifacts, mintCollteralToken, + DMock, } from "../helpers"; -use(smock.matchers); let bondFactory: Contract, collateralToken: Contract, @@ -37,13 +35,10 @@ async function setupContracts() { deployerAddress = await deployer.getAddress(); user = accounts[1]; userAddress = await user.getAddress(); - bondFactory = await setupBondFactory(); ({ collateralToken, rebaseOracle } = await setupCollateralToken("Bitcoin", "BTC")); - const HelpersTester = await ethers.getContractFactory("HelpersTester"); helper = await HelpersTester.deploy(); - await helper.deployed(); } describe("HelpersTester", function () { @@ -52,28 +47,28 @@ describe("HelpersTester", function () { }); after(async function () { - await network.provider.send("hardhat_reset"); + await network.provider.request({ method: "hardhat_reset" }); }); describe("#timeToMatirity", function () { - let maturityDate: number, bondLength: number, bond: Contract; + let maturityDate: BigInt, bondLength: BigInt, bond: Contract; beforeEach(async function () { bondLength = 86400; bond = await createBondWithFactory(bondFactory, collateralToken, [1000], bondLength); - maturityDate = (await bond.maturityDate()).toNumber(); + maturityDate = await bond.maturityDate(); }); describe("when bond is NOT mature", function () { it("should return the time to maturity", async function () { - await TimeHelpers.setNextBlockTimestamp(maturityDate - bondLength / 2); - expect(await helper.secondsToMaturity(bond.address)).to.eq(bondLength / 2); + await TimeHelpers.setNextBlockTimestamp(Number(maturityDate) - bondLength / 2); + expect(await helper.secondsToMaturity(bond.target)).to.eq(bondLength / 2); }); }); describe("when bond is mature", function () { it("should return the time to maturity", async function () { - await TimeHelpers.setNextBlockTimestamp(maturityDate + 1); - expect(await helper.secondsToMaturity(bond.address)).to.eq(0); + await TimeHelpers.setNextBlockTimestamp(Number(maturityDate) + 1); + expect(await helper.secondsToMaturity(bond.target)).to.eq(0); }); }); }); @@ -81,12 +76,12 @@ describe("HelpersTester", function () { describe("#getTranches", function () { it("should revert if bond has more than 2 tranches", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [200, 300, 500], 86400); - await expect(helper.getTranches(bond.address)).to.be.revertedWithCustomError(helper, "UnacceptableTrancheLength"); + await expect(helper.getTranches(bond.target)).to.be.revertedWithCustomError(helper, "UnacceptableTrancheLength"); }); it("should return the tranche data", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [498, 502], 86400); - const td = await helper.getTranches(bond.address); + const td = await helper.getTranches(bond.target); expect(td.tranches.length).to.eq(2); expect(td.trancheRatios.length).to.eq(2); expect(td.trancheRatios[0]).to.eq(498); @@ -100,24 +95,24 @@ describe("HelpersTester", function () { it("should return the tranche when given index", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [100, 100, 100, 100, 100, 500], 86400); for (let i = 0; i < 6; i++) { - expect(await helper.trancheAt(bond.address, i)).to.eq((await bond.tranches(i))[0]); + expect(await helper.trancheAt(bond.target, i)).to.eq((await bond.tranches(i))[0]); } - await expect(helper.trancheAt(bond.address, 7)).to.be.reverted; + await expect(helper.trancheAt(bond.target, 7)).to.be.reverted; }); }); - describe("#getSeniorTranche", function () { + describe("#seniorTranche", function () { it("should return the tranche when given index", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [300, 700], 86400); - const td = await helper.getTranches(bond.address); - expect(await helper.getSeniorTranche(bond.address)).to.eq(td.tranches[0]); + const td = await helper.getTranches(bond.target); + expect(await helper.getSeniorTranche(bond.target)).to.eq(td.tranches[0]); }); }); - describe("#getSeniorTrancheRatio", function () { + describe("#seniorTrancheRatio", function () { it("should return the tranche when given index", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [50, 950], 86400); - const ratio = await helper.getSeniorTrancheRatio(bond.address); + const ratio = await helper.getSeniorTrancheRatio(bond.target); expect(ratio).to.eq(50); }); }); @@ -131,7 +126,7 @@ describe("HelpersTester", function () { describe("if bond is mature", function () { it("should revert", async function () { await bond.mature(); - await expect(helper.previewDeposit(bond.address, toFixedPtAmt("1000"))).to.be.revertedWithCustomError( + await expect(helper.previewDeposit(bond.target, toFixedPtAmt("1000"))).to.be.revertedWithCustomError( helper, "UnacceptableDeposit", ); @@ -140,7 +135,7 @@ describe("HelpersTester", function () { describe("first deposit", function () { it("should calculate the tranche balances after deposit", async function () { - const d = await helper.previewDeposit(bond.address, toFixedPtAmt("1000")); + const d = await helper.previewDeposit(bond.target, toFixedPtAmt("1000")); expect(d[0].amount).to.eq(toFixedPtAmt("500")); expect(d[1].amount).to.eq(toFixedPtAmt("500")); }); @@ -163,7 +158,7 @@ describe("HelpersTester", function () { await rebase(collateralToken, rebaseOracle, 0); }); it("should calculate the tranche balances after deposit", async function () { - const d = await helper.previewDeposit(bond.address, toFixedPtAmt("1000")); + const d = await helper.previewDeposit(bond.target, toFixedPtAmt("1000")); expect(d[0].amount).to.eq(toFixedPtAmt("500")); expect(d[1].amount).to.eq(toFixedPtAmt("500")); }); @@ -181,7 +176,7 @@ describe("HelpersTester", function () { await rebase(collateralToken, rebaseOracle, +0.25); }); it("should calculate the tranche balances after deposit", async function () { - const d = await helper.previewDeposit(bond.address, toFixedPtAmt("1000")); + const d = await helper.previewDeposit(bond.target, toFixedPtAmt("1000")); expect(d[0].amount).to.eq(toFixedPtAmt("400")); expect(d[1].amount).to.eq(toFixedPtAmt("400")); }); @@ -199,7 +194,7 @@ describe("HelpersTester", function () { await rebase(collateralToken, rebaseOracle, -0.5); }); it("should calculate the tranche balances after deposit", async function () { - const d = await helper.previewDeposit(bond.address, toFixedPtAmt("1000")); + const d = await helper.previewDeposit(bond.target, toFixedPtAmt("1000")); expect(d[0].amount).to.eq(toFixedPtAmt("1000")); expect(d[1].amount).to.eq(toFixedPtAmt("1000")); }); @@ -220,7 +215,7 @@ describe("BondTranchesHelpers", function () { }); after(async function () { - await network.provider.send("hardhat_reset"); + await network.provider.request({ method: "hardhat_reset" }); }); describe("#computeRedeemableTrancheAmounts", function () { @@ -237,19 +232,21 @@ describe("BondTranchesHelpers", function () { for (const a in amounts) { await tranches[a].transfer(userAddress, toFixedPtAmt(amounts[a])); } - const b = await helper["computeRedeemableTrancheAmounts(address,address)"](bond.address, userAddress); + const b = await helper["computeRedeemableTrancheAmounts(address,address)"](bond.target, userAddress); for (const a in redemptionAmts) { expect(b[1][a]).to.eq(toFixedPtAmt(redemptionAmts[a])); } - if (b[1][0].gt("0")) { - await bond.connect(user).redeem(b[1]); + if (b[1][0] > 0n) { + await bond.connect(user).redeem([b[1][0], b[1][1]]); } } describe("when the user has the entire supply", function () { describe("[200,800]:[200,800]", async function () { it("should calculate the amounts", async function () { - await checkRedeemableAmts([200, 800], ["200", "800"], ["200", "800"]); + await expect(checkRedeemableAmts([200, 800], ["200", "800"], ["200", "800"])).to.be.revertedWith( + "BondController: Expected minimum valid debt", + ); }); }); }); @@ -265,26 +262,26 @@ describe("BondTranchesHelpers", function () { describe("when the user does not have tranches right proportions", function () { async function checkRedeemableAmts( - trancheRatios: number[] = [], + trancheRatios: BigInt[] = [], amounts: string[] = [], redemptionAmts: string[] = [], ) { const bond = await createBondWithFactory(bondFactory, collateralToken, trancheRatios, 86400); const amt = amounts - .map((a, i) => toFixedPtAmt(a).mul("1000").div(trancheRatios[i])) - .reduce((m, a) => (m.gt(a) ? m : a), toFixedPtAmt("0")); - await depositIntoBond(bond, amt.add(toFixedPtAmt("1")), deployer); + .map((a, i) => (toFixedPtAmt(a) * BigInt("1000")) / BigInt(trancheRatios[i])) + .reduce((m, a) => (m > a ? m : a), 0n); + await depositIntoBond(bond, amt + toFixedPtAmt("1"), deployer); const tranches = await getTranches(bond); for (const a in amounts) { await tranches[a].transfer(userAddress, toFixedPtAmt(amounts[a])); } - const b = await helper["computeRedeemableTrancheAmounts(address,address)"](bond.address, userAddress); + const b = await helper["computeRedeemableTrancheAmounts(address,address)"](bond.target, userAddress); for (const a in redemptionAmts) { expect(b[1][a]).to.eq(toFixedPtAmt(redemptionAmts[a])); } - if (b[1][0].gt("0")) { - await bond.connect(user).redeem(b[1]); + if (b[1][0] > 0n) { + await bond.connect(user).redeem([b[1][0], b[1][1]]); } } @@ -402,7 +399,7 @@ describe("BondTranchesHelpers", function () { ) { bond = await createBondWithFactory(bondFactory, collateralToken, trancheRatios, 86400); const b = await helper["computeRedeemableTrancheAmounts(address,uint256[])"]( - bond.address, + bond.target, amounts.map(toFixedPtAmt), ); for (const a in redemptionAmts) { @@ -447,12 +444,12 @@ describe("BondTranchesHelpers", function () { ) { const bond = await createBondWithFactory(bondFactory, collateralToken, trancheRatios, 86400); const amt = amounts - .map((a, i) => toFixedPtAmt(a).mul("1000").div(trancheRatios[i])) - .reduce((m, a) => (m.gt(a) ? m : a), toFixedPtAmt("0")); - await depositIntoBond(bond, amt.add(toFixedPtAmt("1")), deployer); + .map((a, i) => (toFixedPtAmt(a) * BigInt("1000")) / BigInt(trancheRatios[i])) + .reduce((m, a) => (m > a ? m : a), 0n); + await depositIntoBond(bond, amt + toFixedPtAmt("1"), deployer); const b = await helper["computeRedeemableTrancheAmounts(address,uint256[])"]( - bond.address, + bond.target, amounts.map(toFixedPtAmt), ); for (const a in redemptionAmts) { @@ -571,11 +568,11 @@ describe("TrancheHelpers", function () { }); after(async function () { - await network.provider.send("hardhat_reset"); + await network.provider.request({ method: "hardhat_reset" }); }); describe("#getTrancheCollateralizations", function () { - let bond: Contract, bondLength: number, tranches: Contract[]; + let bond: Contract, bondLength: BigInt, tranches: Contract[]; beforeEach(async function () { bondLength = 86400; bond = await createBondWithFactory(bondFactory, collateralToken, [250, 750], bondLength); @@ -587,7 +584,7 @@ describe("TrancheHelpers", function () { it("should return 0", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [1000], bondLength); const tranches = await getTranches(bond); - await expect(helper.getTrancheCollateralizations(tranches[0].address)).to.be.revertedWithCustomError( + await expect(helper.getTrancheCollateralizations(tranches[0].target)).to.be.revertedWithCustomError( helper, "UnacceptableTrancheLength", ); @@ -598,7 +595,7 @@ describe("TrancheHelpers", function () { it("should return 0", async function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [100, 200, 700], bondLength); const tranches = await getTranches(bond); - await expect(helper.getTrancheCollateralizations(tranches[0].address)).to.be.revertedWithCustomError( + await expect(helper.getTrancheCollateralizations(tranches[0].target)).to.be.revertedWithCustomError( helper, "UnacceptableTrancheLength", ); @@ -610,11 +607,11 @@ describe("TrancheHelpers", function () { const bond = await createBondWithFactory(bondFactory, collateralToken, [333, 667], bondLength); const tranches = await getTranches(bond); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq("0"); expect(t0[1]).to.eq("0"); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq("0"); expect(t1[1]).to.eq("0"); }); @@ -623,11 +620,11 @@ describe("TrancheHelpers", function () { describe("when bond not mature", function () { describe("when no change in supply", function () { it("should calculate the balances", async function () { - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("250")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("750")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -636,10 +633,10 @@ describe("TrancheHelpers", function () { describe("when supply increases above bond threshold", function () { it("should calculate the balances", async function () { await rebase(collateralToken, rebaseOracle, 0.1); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("250")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("850")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -648,10 +645,10 @@ describe("TrancheHelpers", function () { describe("when supply decreases below bond threshold", function () { it("should calculate the balances", async function () { await rebase(collateralToken, rebaseOracle, -0.1); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("250")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("650")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -660,10 +657,10 @@ describe("TrancheHelpers", function () { describe("when supply decreases below junior threshold", function () { it("should calculate the balances", async function () { await rebase(collateralToken, rebaseOracle, -0.8); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("200")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq("0"); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -672,16 +669,16 @@ describe("TrancheHelpers", function () { describe("when bond is mature", function () { beforeEach(async function () { - await TimeHelpers.increaseTime(bondLength); + await TimeHelpers.increaseTime(Number(bondLength)); await bond.mature(); // NOTE: Any rebase after maturity goes directly to the tranches }); describe("when no change in supply", function () { it("should calculate the balances", async function () { - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("250")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("750")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -690,10 +687,10 @@ describe("TrancheHelpers", function () { describe("when supply increases", function () { it("should calculate the balances", async function () { await rebase(collateralToken, rebaseOracle, 0.1); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("275")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("825")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -702,10 +699,10 @@ describe("TrancheHelpers", function () { describe("when supply decreases", function () { it("should calculate the balances", async function () { await rebase(collateralToken, rebaseOracle, -0.1); - const t0 = await helper.getTrancheCollateralizations(tranches[0].address); + const t0 = await helper.getTrancheCollateralizations(tranches[0].target); expect(t0[0]).to.eq(toFixedPtAmt("225")); expect(t0[1]).to.eq(toFixedPtAmt("250")); - const t1 = await helper.getTrancheCollateralizations(tranches[1].address); + const t1 = await helper.getTrancheCollateralizations(tranches[1].target); expect(t1[0]).to.eq(toFixedPtAmt("675")); expect(t1[1]).to.eq(toFixedPtAmt("750")); }); @@ -718,35 +715,32 @@ describe("PerpHelpers", function () { beforeEach(async () => { await setupContracts(); - const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); - perp = await smock.fake(PerpetualTranche); - - const BondController = await getContractFactoryFromExternalArtifacts("BondController"); - depositBond = await smock.fake(BondController); - - const Tranche = await getContractFactoryFromExternalArtifacts("Tranche"); - depositTranche = await smock.fake(Tranche); - - await perp.getDepositBond.returns(depositBond.address); - await perp.totalSupply.returns(toFixedPtAmt("100")); + perp = new DMock(await ethers.getContractFactory("PerpetualTranche")); + await perp.deploy(); + depositBond = new DMock(await getContractFactoryFromExternalArtifacts("BondController")); + await depositBond.deploy(); + depositTranche = new DMock(await getContractFactoryFromExternalArtifacts("Tranche")); + await depositTranche.deploy(); + await perp.mockMethod("getDepositBond()", [depositBond.target]); + await perp.mockMethod("totalSupply()", [toFixedPtAmt("100")]); await mintCollteralToken(collateralToken, toFixedPtAmt("500"), deployer); - await collateralToken.transfer(depositBond.address, toFixedPtAmt("500")); - await depositBond.collateralToken.returns(collateralToken.address); - await depositBond.tranches.whenCalledWith(0).returns([depositTranche.address, 200]); - await depositBond.totalDebt.returns(toFixedPtAmt("500")); - await depositTranche.totalSupply.returns(toFixedPtAmt("100")); + await collateralToken.transfer(depositBond.target, toFixedPtAmt("500")); + await depositBond.mockMethod("collateralToken()", [collateralToken.target]); + await depositBond.mockMethod("tranches(uint256)", [depositTranche.target, 200]); + await depositBond.mockMethod("totalDebt()", [toFixedPtAmt("500")]); + await depositTranche.mockMethod("totalSupply()", [toFixedPtAmt("100")]); }); after(async function () { - await network.provider.send("hardhat_reset"); + await network.provider.request({ method: "hardhat_reset" }); }); describe("when perp price = 1", async function () { describe("when bond cdr = 1", async function () { it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -760,8 +754,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, 0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -775,8 +769,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -790,8 +784,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -804,8 +798,8 @@ describe("PerpHelpers", function () { describe("when perp price > 1", async function () { describe("when bond cdr = 1", async function () { it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("200"), toFixedPtAmt("10"), ); @@ -819,8 +813,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, 0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("200"), toFixedPtAmt("10"), ); @@ -834,8 +828,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("200"), toFixedPtAmt("10"), ); @@ -849,8 +843,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("200"), toFixedPtAmt("10"), ); @@ -863,8 +857,8 @@ describe("PerpHelpers", function () { describe("when perp price < 1", async function () { describe("when bond cdr = 1", async function () { it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("50"), toFixedPtAmt("10"), ); @@ -878,8 +872,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, 0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("50"), toFixedPtAmt("10"), ); @@ -893,8 +887,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("50"), toFixedPtAmt("10"), ); @@ -908,8 +902,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("50"), toFixedPtAmt("10"), ); @@ -921,8 +915,8 @@ describe("PerpHelpers", function () { describe("imperfect rounding", async function () { it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("0.999999999999999999"), ); @@ -933,13 +927,13 @@ describe("PerpHelpers", function () { describe("when perp supply is zero", function () { beforeEach(async function () { - await perp.totalSupply.returns("0"); + await perp.mockMethod("totalSupply()", [0n]); }); describe("when bond cdr = 1", async function () { it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -953,8 +947,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, 0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -968,8 +962,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.1); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -983,8 +977,8 @@ describe("PerpHelpers", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); @@ -996,13 +990,13 @@ describe("PerpHelpers", function () { describe("when deposit bond has no deposits yet", function () { beforeEach(async function () { - await depositBond.totalDebt.returns("0"); - await depositTranche.totalSupply.returns("0"); + await depositBond.mockMethod("totalDebt()", [0n]); + await depositTranche.mockMethod("totalSupply()", [0n]); }); it("should compute the underlying amount", async function () { - const r = await helper.callStatic.estimateUnderlyingAmtToTranche( - perp.address, + const r = await helper.estimateUnderlyingAmtToTranche.staticCall( + perp.target, toFixedPtAmt("100"), toFixedPtAmt("10"), ); diff --git a/spot-contracts/test/_utils/LineHelpers.ts b/spot-contracts/test/_utils/LineHelpers.ts new file mode 100644 index 00000000..47c2cf50 --- /dev/null +++ b/spot-contracts/test/_utils/LineHelpers.ts @@ -0,0 +1,97 @@ +import { ethers } from "hardhat"; +import { expect } from "chai"; +import { Contract } from "ethers"; + +interface Line { + x1: number; + y1: number; + x2: number; + y2: number; +} + +interface Range { + lower: number; + upper: number; +} + +describe("LineHelpers", function () { + let lineHelpersTest: Contract; + + before(async function () { + const TestFactory = await ethers.getContractFactory("LineHelpersTester"); + lineHelpersTest = await TestFactory.deploy(); + }); + + describe("computePiecewiseAvgY", function () { + it("should compute average when xRange is entirely below the breakpoint", async function () { + // Branch: xRange.upper <= xBreakPt + // Use fn1: f(x) = 2x + 5, defined by points (0,5) and (10,25) + // Use fn2: arbitrary (not used in this branch), e.g. f(x) = 3x + 7 + // xRange: lower = 10, upper = 20, xBreakPt = 30 + // Expected: avgY(fn1, [10,20]) = 2*((10+20)/2) + 5 = 35. + const fn1: Line = { x1: 0, y1: 5, x2: 10, y2: 25 }; + const fn2: Line = { x1: 0, y1: 7, x2: 10, y2: 37 }; + const xRange: Range = { lower: 10, upper: 20 }; + const xBreakPt = 30; + const result = await lineHelpersTest.computePiecewiseAvgY(fn1, fn2, xRange, xBreakPt); + expect(result).to.equal(35); + }); + + it("should compute average when xRange is entirely above the breakpoint", async function () { + // Branch: xRange.lower >= xBreakPt + // Use fn2: f(x) = 3x + 7, defined by (0,7) and (10,37) + // xRange: lower = 40, upper = 50, xBreakPt = 30 + // Expected: avgY(fn2, [40,50]) = 3*((40+50)/2) + 7 = 142. + const fn1: Line = { x1: 0, y1: 5, x2: 10, y2: 25 }; // dummy function + const fn2: Line = { x1: 0, y1: 7, x2: 10, y2: 37 }; + const xRange: Range = { lower: 40, upper: 50 }; + const xBreakPt = 30; + const result = await lineHelpersTest.computePiecewiseAvgY(fn1, fn2, xRange, xBreakPt); + expect(result).to.equal(142); + }); + + it("should compute weighted average when xRange spans the breakpoint", async function () { + // Branch: xRange.lower < xBreakPt < xRange.upper + // Use fn1: f(x) = 2x + 5 for [20,30] + // Use fn2: f(x) = 3x + 7 for [30,40] + // xRange: lower = 20, upper = 40, xBreakPt = 30. + // Compute averages: + // avgY(fn1, [20,30]) = 2*((20+30)/2) + 5 = 2*25 + 5 = 55. + // avgY(fn2, [30,40]) = 3*((30+40)/2) + 7 = 3*35 + 7 = 112. + // Weighted average = (55 * (30-20) + 112 * (40-30)) / (40-20) + // = (55*10 + 112*10) / 20 = 1670/20 = 83 (integer division truncates any fraction). + const fn1: Line = { x1: 0, y1: 5, x2: 10, y2: 25 }; + const fn2: Line = { x1: 0, y1: 7, x2: 10, y2: 37 }; + const xRange: Range = { lower: 20, upper: 40 }; + const xBreakPt = 30; + const result = await lineHelpersTest.computePiecewiseAvgY(fn1, fn2, xRange, xBreakPt); + expect(result).to.equal(83); + }); + }); + + describe("avgY", function () { + it("should return the constant y-value for a horizontal line", async function () { + // For a horizontal line f(x) = constant, avgY should return that constant. + // Define a horizontal line f(x) = 10 with points (0,10) and (10,10) + // For any x-range (here [5,15]), the average is 10. + const horizontalLine: Line = { x1: 0, y1: 10, x2: 10, y2: 10 }; + const xL = 5; + const xU = 15; + const result = await lineHelpersTest.avgY(horizontalLine, xL, xU); + expect(result).to.equal(10); + }); + + it("should compute average correctly for a non-horizontal line with fractional average", async function () { + // Test a line with a fractional average result. + // Define line: f(x) = x + 1, using points (0,1) and (3,4) + // For x-range [1,2]: + // m = (4-1)/(3-0) = 1, c = 4 - 1*3 = 1. + // Expected average = 1*((1+2)/2) + 1 = 1*1 + 1 = 2 (due to integer division truncation). + const line: Line = { x1: 0, y1: 1, x2: 3, y2: 4 }; + const xL = 1; + const xU = 2; + const result = await lineHelpersTest.avgY(line, xL, xU); + expect(result).to.equal(2); + }); + }); +}); diff --git a/spot-contracts/test/_utils/Sigmoid.ts b/spot-contracts/test/_utils/Sigmoid.ts index 550e9f8a..0ef75639 100644 --- a/spot-contracts/test/_utils/Sigmoid.ts +++ b/spot-contracts/test/_utils/Sigmoid.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { ethers } from "hardhat"; -import { Contract, BigNumber } from "ethers"; +import { Contract } from "ethers"; import { toPercFixedPtAmt } from "../helpers"; @@ -22,7 +22,6 @@ describe("Sigmoid", function () { before(async function () { const MathTester = await ethers.getContractFactory("MathTester"); math = await MathTester.deploy(); - await math.deployed(); }); it("should return sigmoid(x)", async function () { await cmp(0, 0, -0.01, 0.05, 0); @@ -58,72 +57,71 @@ describe("Sigmoid", function () { before(async function () { const MathTester = await ethers.getContractFactory("MathTester"); math = await MathTester.deploy(); - await math.deployed(); }); - const decimals18 = BigNumber.from("1000000000000000000"); - const decimals10 = BigNumber.from("10000000000"); + const decimals18 = BigInt("1000000000000000000"); + const decimals10 = BigInt("10000000000"); it("2^0", async function () { - const e = BigNumber.from(0); - const one = BigNumber.from(1).mul(decimals18); + const e = 0n; + const one = 1n * decimals18; expect(await math.twoPower(e, one)).to.eq(one); }); it("2^1", async function () { - const e = BigNumber.from(1).mul(decimals18); - const one = BigNumber.from(1).mul(decimals18); - const result = BigNumber.from(2).mul(decimals18); + const e = 1n * decimals18; + const one = 1n * decimals18; + const result = 2n * decimals18; expect(await math.twoPower(e, one)).to.eq(result); }); it("2^30", async function () { - const e = BigNumber.from(30).mul(decimals18); - const one = BigNumber.from(1).mul(decimals18); - const result = BigNumber.from(2 ** 30).mul(decimals18); + const e = 30n * decimals18; + const one = 1n * decimals18; + const result = 2n ** 30n * decimals18; expect(await math.twoPower(e, one)).to.eq(result); }); it("2^2.5", async function () { - const e = BigNumber.from("25000000000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("56568542494"); + const e = BigInt("25000000000"); + const one = 1n * decimals10; + const result = BigInt("56568542494"); expect(await math.twoPower(e, one)).to.eq(result); }); it("2^2.25", async function () { - const e = BigNumber.from("22500000000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("47568284600"); + const e = BigInt("22500000000"); + const one = 1n * decimals10; + const result = BigInt("47568284600"); expect(await math.twoPower(e, one)).to.eq(result); }); it("2^-2.25", async function () { - const e = BigNumber.from("-22500000000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("2102241038"); + const e = BigInt("-22500000000"); + const one = 1n * decimals10; + const result = BigInt("2102241038"); expect(await math.twoPower(e, one)).to.eq(result); }); it("2^-0.6", async function () { - const e = BigNumber.from("-6000000000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("6626183216"); + const e = BigInt("-6000000000"); + const one = 1n * decimals10; + const result = BigInt("6626183216"); expect(await math.twoPower(e, one)).to.eq(result); }); it("2^2.96875", async function () { - const e = BigNumber.from("29687500000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("78285764964"); + const e = BigInt("29687500000"); + const one = 1n * decimals10; + const result = BigInt("78285764964"); expect(await math.twoPower(e, one)).to.eq(result); }); it("2^2.99", async function () { - const e = BigNumber.from("29900000000"); - const one = BigNumber.from(1).mul(decimals10); - const result = BigNumber.from("78285764964"); + const e = BigInt("29900000000"); + const one = 1n * decimals10; + const result = BigInt("78285764964"); expect(await math.twoPower(e, one)).to.eq(result); }); it("should fail on too small exponents", async function () { - const e = BigNumber.from("-1011000000000"); - const one = BigNumber.from(1).mul(decimals10); + const e = BigInt("-1011000000000"); + const one = 1n * decimals10; await expect(math.twoPower(e, one)).to.be.revertedWithCustomError(math, "ExpTooLarge"); }); it("should fail on too large exponents", async function () { - const e = BigNumber.from("1011000000000"); - const one = BigNumber.from(1).mul(decimals10); + const e = BigInt("1011000000000"); + const one = 1n * decimals10; await expect(math.twoPower(e, one)).to.be.revertedWithCustomError(math, "ExpTooLarge"); }); }); diff --git a/spot-contracts/test/helpers.ts b/spot-contracts/test/helpers.ts index 52b40ed6..23d6cc8b 100644 --- a/spot-contracts/test/helpers.ts +++ b/spot-contracts/test/helpers.ts @@ -1,25 +1,27 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import hre, { ethers } from "hardhat"; -import { Signer, Contract, BigNumber, ContractFactory, Transaction, utils } from "ethers"; +import { Signer, Contract, ContractFactory, Transaction } from "ethers"; import * as fs from "fs"; import * as path from "path"; -import { smock, FakeContract } from "@defi-wonderland/smock"; -use(smock.matchers); const TOKEN_DECIMALS = 18; const PRICE_DECIMALS = 8; const DISCOUNT_DECIMALS = 18; const PERC_DECIMALS = 8; -const sciParseFloat = (a: string): BigNumber => (a.includes("e") ? parseFloat(a).toFixed(18) : a); -export const toFixedPtAmt = (a: string): BigNumber => utils.parseUnits(sciParseFloat(a), TOKEN_DECIMALS); -export const toPriceFixedPtAmt = (a: string): BigNumber => utils.parseUnits(sciParseFloat(a), PRICE_DECIMALS); -export const toDiscountFixedPtAmt = (a: string): BigNumber => utils.parseUnits(sciParseFloat(a), DISCOUNT_DECIMALS); -export const toPercFixedPtAmt = (a: string): BigNumber => utils.parseUnits(sciParseFloat(a), PERC_DECIMALS); +const sciParseFloat = (a: string): BigInt => (a.includes("e") ? parseFloat(a).toFixed(18) : a); +export const toFixedPtAmt = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), TOKEN_DECIMALS); +export const toPriceFixedPtAmt = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), PRICE_DECIMALS); +export const toDiscountFixedPtAmt = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), DISCOUNT_DECIMALS); +export const toPercFixedPtAmt = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), PERC_DECIMALS); const ORACLE_BASE_PRICE = toPriceFixedPtAmt("1"); const EXTERNAL_ARTIFACTS_PATH = path.join(__dirname, "/../external-artifacts"); +export const getAbiFromExternalArtifacts = (name: string): Promise => { + const artifact = JSON.parse(fs.readFileSync(`${EXTERNAL_ARTIFACTS_PATH}/${name}.json`).toString()); + return artifact.abi; +}; export const getContractFactoryFromExternalArtifacts = (name: string): Promise => { const artifact = JSON.parse(fs.readFileSync(`${EXTERNAL_ARTIFACTS_PATH}/${name}.json`).toString()); return ethers.getContractFactoryFromArtifact(artifact); @@ -31,26 +33,97 @@ export const TimeHelpers = { }, increaseTime: async (seconds: number): Promise => { - await hre.network.provider.send("evm_increaseTime", [seconds]); - await hre.network.provider.send("evm_mine"); + await hre.network.provider.request({ method: "evm_increaseTime", params: [seconds] }); + await hre.network.provider.request({ method: "evm_mine" }); }, setNextBlockTimestamp: async (timestamp: number): Promise => { - await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]); - await hre.network.provider.send("evm_mine"); + await hre.network.provider.request({ method: "evm_setNextBlockTimestamp", params: [timestamp] }); + await hre.network.provider.request({ method: "evm_mine" }); }, currentTime: async (): Promise => { - const res = await hre.network.provider.send("eth_getBlockByNumber", ["latest", false]); + const res = await hre.network.provider.request({ method: "eth_getBlockByNumber", params: ["latest", false] }); const timestamp = parseInt(res.timestamp, 16); return timestamp; }, }; +export interface DMockMethod { + methodName: string; + parameters: any[]; + returnType: string; + returnValue: any; +} + +export class DMock { + private refFactory: string; + private contract: Contract | null = null; + private target: string | null = null; + + constructor(refFactory: ContractFactory) { + this.refFactory = refFactory; + } + + public async deploy(): Promise { + this.contract = await (await ethers.getContractFactory("DMock")).deploy(); + this.target = this.contract.target; + } + + public async mockMethod(methodFragment: string, returnValue: any = []): Promise { + if (!this.contract) { + await this.deploy(); + } + const methodFragmentObj = this.refFactory.interface.fragments.filter( + f => f.type === "function" && f.format("sighash") === methodFragment, + )[0]; + if (!methodFragmentObj) { + throw Error(`Unkown function fragment ${methodFragment}, not part of the contract abi`); + } + const encodedReturnValue = ethers.AbiCoder.defaultAbiCoder().encode(methodFragmentObj.outputs, returnValue); + await this.contract.mockMethod(methodFragmentObj.selector, encodedReturnValue); + } + + public async clearMockMethod(methodFragment: string): Promise { + if (!this.contract) { + await this.deploy(); + } + const methodFragmentObj = this.refFactory.interface.fragments.filter( + f => f.type === "function" && f.format("sighash") === methodFragment, + )[0]; + if (!methodFragmentObj) { + throw Error(`Unkown function fragment ${methodFragment}, not part of the contract abi`); + } + await this.contract.clearMockMethodSig(methodFragmentObj.selector); + } + + public async mockCall(methodFragment: string, parameters: any, returnValue: any = []): Promise { + if (!this.contract) { + await this.deploy(); + } + const methodFragmentObj = this.refFactory.interface.fragments.filter( + f => f.type === "function" && f.format("sighash") === methodFragment, + )[0]; + if (!methodFragmentObj) { + throw Error(`Unkown function fragment ${methodFragment}, not part of the contract abi`); + } + const encodedData = this.refFactory.interface.encodeFunctionData(methodFragmentObj, parameters); + await this.contract.mockCall( + encodedData, + ethers.AbiCoder.defaultAbiCoder().encode(methodFragmentObj.outputs, returnValue), + ); + } + + public async staticCall(methodFragment: string, parameters: any = []): Promise { + const mock = this.refFactory.attach(this.contract.target); + return mock[methodFragment].staticCall(...parameters); + } +} + // Rebasing collateral token (button tokens) interface ButtonTokenContracts { underlyingToken: Contract; - rebaseOracle: FakeContract; + rebaseOracle: Contract; collateralToken: Contract; } export const setupCollateralToken = async (name: string, symbol: string): Promise => { @@ -58,13 +131,13 @@ export const setupCollateralToken = async (name: string, symbol: string): Promis const underlyingToken = await ERC20.deploy(); await underlyingToken.init(name, symbol); - const MedianOracle = await getContractFactoryFromExternalArtifacts("MedianOracle"); - const rebaseOracle = await smock.fake(MedianOracle); - await rebaseOracle.getData.returns([ORACLE_BASE_PRICE, true]); + const rebaseOracle = new DMock(await getContractFactoryFromExternalArtifacts("MedianOracle")); + await rebaseOracle.deploy(); + await rebaseOracle.mockMethod("getData()", [ORACLE_BASE_PRICE, true]); const ButtonToken = await getContractFactoryFromExternalArtifacts("ButtonToken"); const collateralToken = await ButtonToken.deploy(); - await collateralToken.initialize(underlyingToken.address, `Button ${name}`, `btn-${symbol}`, rebaseOracle.address); + await collateralToken.initialize(underlyingToken.target, `Button ${name}`, `btn-${symbol}`, rebaseOracle.target); return { underlyingToken, @@ -73,20 +146,21 @@ export const setupCollateralToken = async (name: string, symbol: string): Promis }; }; -export const mintCollteralToken = async (collateralToken: Contract, amount: BigNumber, from: Signer) => { +export const mintCollteralToken = async (collateralToken: Contract, amount: BigInt, from: Signer) => { const fromAddress = await from.getAddress(); const ERC20 = await ethers.getContractFactory("MockERC20"); const underlyingToken = await ERC20.attach(await collateralToken.underlying()); const cAmount = await collateralToken.wrapperToUnderlying(amount); await underlyingToken.connect(from).mint(fromAddress, cAmount); - await underlyingToken.connect(from).approve(collateralToken.address, cAmount); + await underlyingToken.connect(from).approve(collateralToken.target, cAmount); await collateralToken.connect(from).mint(amount); }; -export const rebase = async (token: Contract, oracle: FakeContract, perc: number) => { +export const rebase = async (token: Contract, oracle: Contract, perc: number) => { const p = await token.lastPrice(); - const newPrice = p.mul(ORACLE_BASE_PRICE.add(ORACLE_BASE_PRICE.toNumber() * perc)).div(ORACLE_BASE_PRICE); - await oracle.getData.returns([newPrice, true]); + const delta = BigInt(Number(ORACLE_BASE_PRICE) * perc); + const newPrice = (p * (ORACLE_BASE_PRICE + delta)) / ORACLE_BASE_PRICE; + await oracle.mockMethod("getData()", [newPrice, true]); await token.rebase(); }; @@ -94,20 +168,15 @@ export const rebase = async (token: Contract, oracle: FakeContract, perc: number export const setupBondFactory = async (): Promise => { const BondController = await getContractFactoryFromExternalArtifacts("BondController"); const bondController = await BondController.deploy(); - await bondController.deployed(); const Tranche = await getContractFactoryFromExternalArtifacts("Tranche"); const tranche = await Tranche.deploy(); - await tranche.deployed(); const TrancheFactory = await getContractFactoryFromExternalArtifacts("TrancheFactory"); - const trancheFactory = await TrancheFactory.deploy(tranche.address); - await trancheFactory.deployed(); + const trancheFactory = await TrancheFactory.deploy(tranche.target); const BondFactory = await getContractFactoryFromExternalArtifacts("BondFactory"); - const bondFactory = await BondFactory.deploy(bondController.address, trancheFactory.address); - await bondFactory.deployed(); - + const bondFactory = await BondFactory.deploy(bondController.target, trancheFactory.target); return bondFactory; }; @@ -129,31 +198,29 @@ export const createBondWithFactory = async ( ): Promise => { const timeNow = await TimeHelpers.secondsFromNow(0); const maturityDate = timeNow + bondLength; - - const bondAddress = await bondFactory.callStatic.createBond(collateralToken.address, trancheRatios, maturityDate); - await bondFactory.createBond(collateralToken.address, trancheRatios, maturityDate); - + const bondAddress = await bondFactory.createBond.staticCall(collateralToken.target, trancheRatios, maturityDate); + await bondFactory.createBond(collateralToken.target, trancheRatios, maturityDate); return bondAt(bondAddress); }; // Bond interaction helpers export interface BondDeposit { - amount: BigNumber; - feeBps: BigNumber; + amount: BigInt; + feeBps: BigInt; from: string; } -export const depositIntoBond = async (bond: Contract, amount: BigNumber, from: Signer): Promise => { +export const depositIntoBond = async (bond: Contract, amount: BigInt, from: Signer): Promise => { const ButtonToken = await getContractFactoryFromExternalArtifacts("ButtonToken"); const collateralToken = await ButtonToken.attach(await bond.collateralToken()); await mintCollteralToken(collateralToken, amount, from); - await collateralToken.connect(from).approve(bond.address, amount); + await collateralToken.connect(from).approve(bond.target, amount); const tx = await bond.connect(from).deposit(amount); const txR = await tx.wait(); - const depositEvent = txR.events[txR.events.length - 1].args; + const depositEvent = txR.logs[txR.logs.length - 1].args; return depositEvent; }; @@ -168,9 +235,9 @@ export const getTranches = async (bond: Contract): Promise => { return tranches; }; -export const getTrancheBalances = async (bond: Contract, user: string): Promise => { +export const getTrancheBalances = async (bond: Contract, user: string): Promise => { const tranches = await getTranches(bond); - const balances: BigNumber[] = []; + const balances: BigInt[] = []; for (let i = 0; i < tranches.length; i++) { balances.push(await tranches[i].balanceOf(user)); } @@ -178,11 +245,11 @@ export const getTrancheBalances = async (bond: Contract, user: string): Promise< }; export const timeToMaturity = async (bond: Contract): Promise => { - return (await bond.maturityDate()).toNumber() - (await TimeHelpers.currentTime()); + return Number(await bond.maturityDate()) - (await TimeHelpers.currentTime()); }; export const getDepositBond = async (perp: Contract): Contract => { - return bondAt(await perp.callStatic.getDepositBond()); + return bondAt(await perp.getDepositBond.staticCall()); }; export const advanceTime = async (time: number): Promise => { @@ -197,7 +264,7 @@ export const advancePerpQueue = async (perp: Contract, time: number): Promise => { await perp.updateState(); const matuirtyDate = await bond.maturityDate(); - await TimeHelpers.setNextBlockTimestamp(matuirtyDate.toNumber()); + await TimeHelpers.setNextBlockTimestamp(Number(matuirtyDate)); }; export const advancePerpQueueToBondMaturity = async (perp: Contract, bond: Contract): Promise => { @@ -210,60 +277,60 @@ export const advancePerpQueueToRollover = async (perp: Contract, bond: Contract) await perp.updateState(); const bufferSec = await perp.minTrancheMaturitySec(); const matuirtyDate = await bond.maturityDate(); - await TimeHelpers.setNextBlockTimestamp(matuirtyDate.sub(bufferSec).toNumber()); + await TimeHelpers.setNextBlockTimestamp(Number(matuirtyDate - bufferSec)); await perp.updateState(); await TimeHelpers.increaseTime(1); return perp.updateState(); }; -export const logReserveComposition = async (perp: Contract) => { +export const logPerpAssets = async (perp: Contract) => { const ERC20 = await ethers.getContractFactory("MockERC20"); - const count = await perp.callStatic.getReserveCount(); - console.log("Reserve count", count); + const count = await perp.getReserveCount.staticCall(); + console.log("Perp assets", count); for (let i = 0; i < count; i++) { - const token = await ERC20.attach(await perp.callStatic.getReserveAt(i)); - const ONE = BigNumber.from(`${10 ** (await perp.decimals())}`); - const tokenVal = await perp.callStatic.getReserveTokenValue(token.address); - const tokenBal = await perp.callStatic.getReserveTokenBalance(token.address); - const tokenPrice = tokenBal.gt("0") ? tokenVal.mul(ONE).div(tokenBal) : BigNumber.from(0); + const token = await ERC20.attach(await perp.getReserveAt.staticCall(i)); + const ONE = ethers.parseUnits("1", await perp.decimals()); + const tokenVal = await perp.getReserveTokenValue.staticCall(token.target); + const tokenBal = await perp.getReserveTokenBalance.staticCall(token.target); + const tokenPrice = tokenBal > 0n ? (tokenVal * ONE) / tokenBal : 0n; console.log( i, - token.address, - utils.formatUnits(await token.balanceOf(perp.address), await perp.decimals()), - utils.formatUnits(tokenPrice, await perp.decimals()), + token.target, + ethers.formatUnits(await token.balanceOf(perp.target), await perp.decimals()), + ethers.formatUnits(tokenPrice, await perp.decimals()), ); } }; -export const checkReserveComposition = async (perp: Contract, tokens: Contract[], balances: BigNumber[] = []) => { +export const checkPerpComposition = async (perp: Contract, tokens: Contract[], balances: BigInt[] = []) => { const checkBalances = balances.length > 0; - expect(await perp.callStatic.getReserveCount()).to.eq(tokens.length); + expect(await perp.getReserveCount.staticCall()).to.eq(tokens.length); const tokenMap = {}; const tokenBalanceMap = {}; for (const i in tokens) { - tokenMap[tokens[i].address] = true; + tokenMap[tokens[i].target] = true; if (checkBalances) { - tokenBalanceMap[tokens[i].address] = balances[i]; + tokenBalanceMap[tokens[i].target] = balances[i]; } } const ERC20 = await ethers.getContractFactory("MockERC20"); for (let j = 0; j < tokens.length; j++) { - const reserveToken = ERC20.attach(await perp.callStatic.getReserveAt(j)); - expect(tokenMap[reserveToken.address]).to.eq(true); + const reserveToken = ERC20.attach(await perp.getReserveAt.staticCall(j)); + expect(tokenMap[reserveToken.target]).to.eq(true); if (checkBalances) { - expect(await reserveToken.balanceOf(perp.address)).to.eq(tokenBalanceMap[reserveToken.address]); + expect(await reserveToken.balanceOf(perp.target)).to.eq(tokenBalanceMap[reserveToken.target]); } } - await expect(perp.callStatic.getReserveAt(tokens.length)).to.be.reverted; + await expect(perp.getReserveAt.staticCall(tokens.length)).to.be.reverted; }; export const getReserveTokens = async (perp: Contract) => { const ERC20 = await ethers.getContractFactory("MockERC20"); const reserves: Contract[] = []; - for (let i = 0; i < (await perp.callStatic.getReserveCount()); i++) { - reserves.push(await ERC20.attach(await perp.callStatic.getReserveAt(i))); + for (let i = 0; i < (await perp.getReserveCount()); i++) { + reserves.push(await ERC20.attach(await perp.getReserveAt.staticCall(i))); } return reserves; }; @@ -272,28 +339,28 @@ export const logVaultAssets = async (vault: Contract) => { const ERC20 = await ethers.getContractFactory("MockERC20"); const count = await vault.assetCount(); const assetCount = await vault.assetCount(); - console.log("Asset count", count); + console.log("Vault assets", count); const underlying = await ERC20.attach(await vault.underlying()); console.log( 0, - underlying.address, - utils.formatUnits(await vault.vaultAssetBalance(underlying.address), await underlying.decimals()), + underlying.target, + ethers.formatUnits(await vault.vaultAssetBalance(underlying.target), await underlying.decimals()), ); for (let i = 1; i < assetCount; i++) { const token = await ERC20.attach(await vault.assetAt(i)); console.log( i + 1, - token.address, - utils.formatUnits(await vault.vaultAssetBalance(token.address), await token.decimals()), + token.target, + ethers.formatUnits(await vault.vaultAssetBalance(token.target), await token.decimals()), ); } }; -export const checkVaultAssetComposition = async (vault: Contract, tokens: Contract[], balances: BigNumber[] = []) => { +export const checkVaultComposition = async (vault: Contract, tokens: Contract[], balances: BigInt[] = []) => { expect(await vault.assetCount()).to.eq(tokens.length); for (const i in tokens) { - expect(await vault.vaultAssetBalance(tokens[i].address)).to.eq(balances[i]); + expect(await vault.vaultAssetBalance(tokens[i].target)).to.eq(balances[i]); } }; diff --git a/spot-contracts/test/perp/PerpetualTranche.ts b/spot-contracts/test/perp/PerpetualTranche.ts index 85a48f71..71055038 100644 --- a/spot-contracts/test/perp/PerpetualTranche.ts +++ b/spot-contracts/test/perp/PerpetualTranche.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; -import { Contract, Transaction, Signer, constants } from "ethers"; -import { smock } from "@defi-wonderland/smock"; +import { Contract, Transaction, Signer } from "ethers"; import { setupCollateralToken, setupBondFactory, @@ -11,13 +10,13 @@ import { toFixedPtAmt, advancePerpQueue, bondAt, - checkReserveComposition, + checkPerpComposition, TimeHelpers, rebase, advancePerpQueueToRollover, toPercFixedPtAmt, + DMock, } from "../helpers"; -use(smock.matchers); let perp: Contract, collateralToken: Contract, @@ -36,27 +35,37 @@ describe("PerpetualTranche", function () { ({ collateralToken, rebaseOracle } = await setupCollateralToken("Bitcoin", "BTC")); - const BondIssuer = await ethers.getContractFactory("BondIssuer"); - issuer = await smock.fake(BondIssuer); - await issuer.collateral.returns(collateralToken.address); + issuer = new DMock(await ethers.getContractFactory("BondIssuer")); + await issuer.deploy(); + await issuer.mockMethod("collateral()", [collateralToken.target]); + await issuer.mockMethod("getLatestBond()", [ethers.ZeroAddress]); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, ); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - const vault = await smock.fake(RolloverVault); - await vault.getTVL.returns("0"); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + const vault = new DMock(RolloverVault); + await vault.deploy(); + await vault.mockMethod("getTVL()", [0]); + await perp.updateVault(vault.target); }); afterEach(async function () { @@ -75,22 +84,22 @@ describe("PerpetualTranche", function () { }); it("should set ext service references", async function () { - expect(await perp.bondIssuer()).to.eq(issuer.address); - expect(await perp.feePolicy()).to.eq(feePolicy.address); + expect(await perp.bondIssuer()).to.eq(issuer.target); + expect(await perp.feePolicy()).to.eq(feePolicy.target); }); it("should set underlying collateral reference", async function () { - expect(await perp.underlying()).to.eq(collateralToken.address); + expect(await perp.underlying()).to.eq(collateralToken.target); }); it("should initialize lists", async function () { - expect(await perp.callStatic.getReserveCount()).to.eq(1); + expect(await perp.getReserveCount.staticCall()).to.eq(1); }); it("should set hyper parameters", async function () { - expect(await perp.minTrancheMaturitySec()).to.eq(1); - expect(await perp.maxTrancheMaturitySec()).to.eq(constants.MaxUint256); - expect(await perp.maxSupply()).to.eq(constants.MaxUint256); + expect(await perp.minTrancheMaturitySec()).to.eq(86400 * 7); + expect(await perp.maxTrancheMaturitySec()).to.eq(86400 * 31); + expect(await perp.maxSupply()).to.eq(ethers.MaxUint256); expect(await perp.maxDepositTrancheValuePerc()).to.eq(toPercFixedPtAmt("1")); }); @@ -181,7 +190,7 @@ describe("PerpetualTranche", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).updateKeeper(constants.AddressZero)).to.be.revertedWith( + await expect(perp.connect(otherUser).updateKeeper(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -201,7 +210,7 @@ describe("PerpetualTranche", function () { describe("#updateVault", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).updateVault(constants.AddressZero)).to.be.revertedWith( + await expect(perp.connect(otherUser).updateVault(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -210,15 +219,22 @@ describe("PerpetualTranche", function () { describe("when vault reference is set", function () { let tx: Transaction, vault: Contract; beforeEach(async function () { - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await smock.fake(RolloverVault); - await vault.getTVL.returns(0); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + vault = new DMock(RolloverVault); + await vault.deploy(); + await vault.mockMethod("getTVL()", [0]); - tx = perp.connect(deployer).updateVault(vault.address); + tx = perp.connect(deployer).updateVault(vault.target); await tx; }); it("should update vault reference", async function () { - expect(await perp.vault()).to.eq(vault.address); + expect(await perp.vault()).to.eq(vault.target); }); }); }); @@ -228,7 +244,7 @@ describe("PerpetualTranche", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).updateBondIssuer(constants.AddressZero)).to.be.revertedWith( + await expect(perp.connect(otherUser).updateBondIssuer(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -236,25 +252,26 @@ describe("PerpetualTranche", function () { describe("when set address is valid", function () { beforeEach(async function () { - const BondIssuer = await ethers.getContractFactory("BondIssuer"); - newIssuer = await smock.fake(BondIssuer); - await newIssuer.collateral.returns(collateralToken.address); - tx = perp.updateBondIssuer(newIssuer.address); + newIssuer = new DMock(await ethers.getContractFactory("BondIssuer")); + await newIssuer.deploy(); + await newIssuer.mockMethod("collateral()", [collateralToken.target]); + + tx = perp.updateBondIssuer(newIssuer.target); await tx; }); it("should update reference", async function () { - expect(await perp.bondIssuer()).to.eq(newIssuer.address); + expect(await perp.bondIssuer()).to.eq(newIssuer.target); }); }); describe("when collateral is NOT valid", function () { beforeEach(async function () { - const BondIssuer = await ethers.getContractFactory("BondIssuer"); - newIssuer = await smock.fake(BondIssuer); - await newIssuer.collateral.returns(constants.AddressZero); + newIssuer = new DMock(await ethers.getContractFactory("BondIssuer")); + await newIssuer.deploy(); + await newIssuer.mockMethod("collateral()", [ethers.ZeroAddress]); }); it("should revert", async function () { - await expect(perp.updateBondIssuer(newIssuer.address)).to.be.revertedWithCustomError(perp, "UnexpectedAsset"); + await expect(perp.updateBondIssuer(newIssuer.target)).to.be.revertedWithCustomError(perp, "UnexpectedAsset"); }); }); }); @@ -264,7 +281,7 @@ describe("PerpetualTranche", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).updateFeePolicy(constants.AddressZero)).to.be.revertedWith( + await expect(perp.connect(otherUser).updateFeePolicy(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -272,10 +289,10 @@ describe("PerpetualTranche", function () { describe("when set strategy decimals dont match", function () { it("should revert", async function () { - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - newFeePolicy = await smock.fake(FeePolicy); - await newFeePolicy.decimals.returns(7); - await expect(perp.updateFeePolicy(newFeePolicy.address)).to.be.revertedWithCustomError( + newFeePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await newFeePolicy.deploy(); + await newFeePolicy.mockMethod("decimals()", [7]); + await expect(perp.updateFeePolicy(newFeePolicy.target)).to.be.revertedWithCustomError( perp, "UnexpectedDecimals", ); @@ -284,14 +301,14 @@ describe("PerpetualTranche", function () { describe("when set address is valid", function () { beforeEach(async function () { - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - newFeePolicy = await smock.fake(FeePolicy); - await newFeePolicy.decimals.returns(8); - tx = perp.updateFeePolicy(newFeePolicy.address); + newFeePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await newFeePolicy.deploy(); + await newFeePolicy.mockMethod("decimals()", [8]); + tx = perp.updateFeePolicy(newFeePolicy.target); await tx; }); it("should update reference", async function () { - expect(await perp.feePolicy()).to.eq(newFeePolicy.address); + expect(await perp.feePolicy()).to.eq(newFeePolicy.target); }); }); }); @@ -333,7 +350,7 @@ describe("PerpetualTranche", function () { describe("when triggered by non-keeper", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).updateMaxSupply(constants.MaxUint256)).to.be.revertedWithCustomError( + await expect(perp.connect(otherUser).updateMaxSupply(ethers.MaxUint256)).to.be.revertedWithCustomError( perp, "UnauthorizedCall", ); @@ -391,13 +408,13 @@ describe("PerpetualTranche", function () { const Token = await ethers.getContractFactory("MockERC20"); transferToken = await Token.deploy(); await transferToken.init("Mock Token", "MOCK"); - await transferToken.mint(perp.address, "100"); + await transferToken.mint(perp.target, "100"); toAddress = await deployer.getAddress(); }); describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(perp.connect(otherUser).transferERC20(transferToken.address, toAddress, "100")).to.be.revertedWith( + await expect(perp.connect(otherUser).transferERC20(transferToken.target, toAddress, "100")).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -405,7 +422,7 @@ describe("PerpetualTranche", function () { describe("when non reserve asset", function () { it("should transfer", async function () { - await expect(() => perp.transferERC20(transferToken.address, toAddress, "100")).to.changeTokenBalance( + await expect(() => perp.transferERC20(transferToken.target, toAddress, "100")).to.changeTokenBalance( transferToken, deployer, "100", @@ -415,9 +432,9 @@ describe("PerpetualTranche", function () { describe("when reserve asset", function () { it("should revert", async function () { - expect(await perp.callStatic.inReserve(collateralToken.address)).to.eq(true); + expect(await perp.inReserve.staticCall(collateralToken.target)).to.eq(true); await expect( - perp.transferERC20(collateralToken.address, toAddress, toFixedPtAmt("100")), + perp.transferERC20(collateralToken.target, toAddress, toFixedPtAmt("100")), ).to.be.revertedWithCustomError(perp, "UnauthorizedTransferOut"); }); }); @@ -427,12 +444,13 @@ describe("PerpetualTranche", function () { const bondFactory = await setupBondFactory(); const bond = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 3600); const tranches = await getTranches(bond); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); + await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranches[0].address, toFixedPtAmt("100")); - await perp.transfer(perp.address, toFixedPtAmt("100")); - await expect(perp.transferERC20(perp.address, toAddress, toFixedPtAmt("100"))).not.to.be.reverted; + await tranches[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranches[0].target, toFixedPtAmt("100")); + await perp.transfer(perp.target, toFixedPtAmt("100")); + await expect(perp.transferERC20(perp.target, toAddress, toFixedPtAmt("100"))).not.to.be.reverted; }); }); }); @@ -445,10 +463,10 @@ describe("PerpetualTranche", function () { describe("when reserve has no tranches", function () { it("should have expected reserve composition", async function () { - await checkReserveComposition(perp, [collateralToken], ["0"]); + await checkPerpComposition(perp, [collateralToken], ["0"]); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(0); + expect(await perp.getTVL.staticCall()).to.eq(0); }); }); @@ -456,18 +474,18 @@ describe("PerpetualTranche", function () { beforeEach(async function () { bond = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 3600); tranches = await getTranches(bond); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); }); it("should have expected reserve composition", async function () { - await checkReserveComposition(perp, [collateralToken, tranches[0]], ["0", toFixedPtAmt("200")]); + await checkPerpComposition(perp, [collateralToken, tranches[0]], ["0", toFixedPtAmt("200")]); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("200")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("200")); }); }); @@ -475,32 +493,32 @@ describe("PerpetualTranche", function () { beforeEach(async function () { bond = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 3600); tranches = await getTranches(bond); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await rebase(collateralToken, rebaseOracle, -0.9); bondNext = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 3600); tranchesNext = await getTranches(bondNext); - await issuer.getLatestBond.returns(bondNext.address); + await issuer.mockMethod("getLatestBond()", [bondNext.target]); await depositIntoBond(bondNext, toFixedPtAmt("1000"), deployer); - await tranchesNext[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranchesNext[0].address, toFixedPtAmt("100")); + await tranchesNext[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranchesNext[0].target, toFixedPtAmt("100")); }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, tranches[0], tranchesNext[0]], ["0", toFixedPtAmt("200"), toFixedPtAmt("100")], ); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("200")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("200")); }); }); @@ -510,37 +528,37 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await advancePerpQueue(perp, 1200); - bond = await bondAt(await perp.callStatic.getDepositBond()); + bond = await bondAt(await perp.getDepositBond.staticCall()); tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await advancePerpQueue(perp, 1200); - bondNext = await bondAt(await perp.callStatic.getDepositBond()); + bondNext = await bondAt(await perp.getDepositBond.staticCall()); tranchesNext = await getTranches(bondNext); await depositIntoBond(bondNext, toFixedPtAmt("1000"), deployer); - await tranchesNext[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranchesNext[0].address, toFixedPtAmt("100")); + await tranchesNext[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranchesNext[0].target, toFixedPtAmt("100")); await advancePerpQueue(perp, 36000); }); it("should have expected reserve composition", async function () { - await checkReserveComposition(perp, [collateralToken], [toFixedPtAmt("300")]); + await checkPerpComposition(perp, [collateralToken], [toFixedPtAmt("300")]); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("300")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("300")); }); }); @@ -550,41 +568,41 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await advancePerpQueue(perp, 3600); - bond = await bondAt(await perp.callStatic.getDepositBond()); + bond = await bondAt(await perp.getDepositBond.staticCall()); tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await advancePerpQueue(perp, 1200); - bondNext = await bondAt(await perp.callStatic.getDepositBond()); + bondNext = await bondAt(await perp.getDepositBond.staticCall()); tranchesNext = await getTranches(bondNext); await depositIntoBond(bondNext, toFixedPtAmt("1000"), deployer); - await tranchesNext[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranchesNext[0].address, toFixedPtAmt("100")); + await tranchesNext[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranchesNext[0].target, toFixedPtAmt("100")); await advancePerpQueue(perp, 2400); }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, tranchesNext[0]], [toFixedPtAmt("200"), toFixedPtAmt("100")], ); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("300")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("300")); }); }); @@ -594,27 +612,27 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await advancePerpQueue(perp, 3600); - bond = await bondAt(await perp.callStatic.getDepositBond()); + bond = await bondAt(await perp.getDepositBond.staticCall()); tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await advancePerpQueue(perp, 1200); - bondNext = await bondAt(await perp.callStatic.getDepositBond()); + bondNext = await bondAt(await perp.getDepositBond.staticCall()); tranchesNext = await getTranches(bondNext); await depositIntoBond(bondNext, toFixedPtAmt("1000"), deployer); - await tranchesNext[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranchesNext[0].address, toFixedPtAmt("100")); + await tranchesNext[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranchesNext[0].target, toFixedPtAmt("100")); await advancePerpQueue(perp, 2400); @@ -622,14 +640,14 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, tranchesNext[0]], [toFixedPtAmt("220"), toFixedPtAmt("100")], ); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("320")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("320")); }); }); @@ -639,28 +657,28 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await advancePerpQueue(perp, 3600); - bond = await bondAt(await perp.callStatic.getDepositBond()); + bond = await bondAt(await perp.getDepositBond.staticCall()); tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await advancePerpQueue(perp, 1200); - bondNext = await bondAt(await perp.callStatic.getDepositBond()); + bondNext = await bondAt(await perp.getDepositBond.staticCall()); tranchesNext = await getTranches(bondNext); await depositIntoBond(bondNext, toFixedPtAmt("1000"), deployer); - await tranchesNext[0].approve(perp.address, toFixedPtAmt("100")); - await perp.deposit(tranchesNext[0].address, toFixedPtAmt("100")); + await tranchesNext[0].approve(perp.target, toFixedPtAmt("100")); + await perp.deposit(tranchesNext[0].target, toFixedPtAmt("100")); await advancePerpQueue(perp, 2400); @@ -668,14 +686,14 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, tranchesNext[0]], [toFixedPtAmt("180"), toFixedPtAmt("100")], ); }); it("should calculate the tvl", async function () { - expect(await perp.callStatic.getTVL()).to.eq(toFixedPtAmt("280")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("280")); }); }); }); @@ -693,12 +711,12 @@ describe("PerpetualTranche", function () { beforeEach(async function () { await perp.updateTolerableTrancheMaturity(1200, 7200); bond = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 7210); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); await perp.updateState(); }); it("should NOT update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.not.eq(bond.address); + expect(await perp.getDepositBond.staticCall()).to.not.eq(bond.target); }); }); @@ -707,12 +725,12 @@ describe("PerpetualTranche", function () { await perp.updateTolerableTrancheMaturity(1200, 7200); const r = await setupCollateralToken("Ethereum", "ETH"); bond = await createBondWithFactory(bondFactory, r.collateralToken, [200, 800], 3600); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); await perp.updateState(); }); it("should NOT update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.not.eq(bond.address); + expect(await perp.getDepositBond.staticCall()).to.not.eq(bond.target); }); }); @@ -721,17 +739,17 @@ describe("PerpetualTranche", function () { beforeEach(async function () { await perp.updateTolerableTrancheMaturity(1200, 7200); bond = await createBondWithFactory(bondFactory, collateralToken, [200, 800], 3600); - await issuer.getLatestBond.returns(bond.address); + await issuer.mockMethod("getLatestBond()", [bond.target]); tx = perp.updateState(); await tx; }); it("should update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.eq(bond.address); + expect(await perp.getDepositBond.staticCall()).to.eq(bond.target); }); it("should emit event", async function () { - await expect(tx).to.emit(perp, "UpdatedDepositBond").withArgs(bond.address); + await expect(tx).to.emit(perp, "UpdatedDepositBond").withArgs(bond.target); }); }); }); @@ -743,26 +761,26 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(0, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); reserveTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -775,8 +793,8 @@ describe("PerpetualTranche", function () { ], ); - expect(await perp.callStatic.getReserveCount()).to.eq("6"); - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); await TimeHelpers.increaseTime(1200); tx = await perp.updateState(); @@ -784,7 +802,7 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -799,17 +817,17 @@ describe("PerpetualTranche", function () { }); it("should NOT change reserveCount", async function () { - expect(await perp.callStatic.getReserveCount()).to.eq("6"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); }); it("should NOT change tranche balances", async function () {}); it("should emit ReserveSynced", async function () { - await expect(tx).to.emit(perp, "ReserveSynced").withArgs(collateralToken.address, "0"); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(collateralToken.target, "0"); }); it("should NOT update the reserve balance", async function () { - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); }); }); @@ -821,25 +839,25 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(0, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); reserveTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -851,8 +869,8 @@ describe("PerpetualTranche", function () { toFixedPtAmt("500"), ], ); - expect(await perp.callStatic.getReserveCount()).to.eq("6"); - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); await TimeHelpers.increaseTime(6000); // NOTE: invoking mature on reserveTranches[0], @@ -864,7 +882,7 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranches[3], reserveTranches[4], reserveTranches[2]], [toFixedPtAmt("1000"), toFixedPtAmt("500"), toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -872,27 +890,27 @@ describe("PerpetualTranche", function () { }); it("should change reserveCount", async function () { - expect(await perp.callStatic.getReserveCount()).to.eq("4"); + expect(await perp.getReserveCount.staticCall()).to.eq("4"); }); it("should call mature if not already called", async function () { await expect(tx) .to.emit(await bondAt(await reserveTranches[1].bond()), "Mature") - .withArgs(perp.address); + .withArgs(perp.target); }); it("should emit ReserveSynced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("1000")) + .withArgs(collateralToken.target, toFixedPtAmt("1000")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[0].address, "0") + .withArgs(reserveTranches[0].target, "0") .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[1].address, "0"); + .withArgs(reserveTranches[1].target, "0"); }); it("should update the reserve balance", async function () { - expect(await collateralToken.balanceOf(perp.address)).to.eq(toFixedPtAmt("1000")); + expect(await collateralToken.balanceOf(perp.target)).to.eq(toFixedPtAmt("1000")); }); }); @@ -904,26 +922,26 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(0, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); reserveTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); await rebase(collateralToken, rebaseOracle, -0.25); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -935,8 +953,8 @@ describe("PerpetualTranche", function () { toFixedPtAmt("500"), ], ); - expect(await perp.callStatic.getReserveCount()).to.eq("6"); - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); await TimeHelpers.increaseTime(6000); tx = perp.updateState(); @@ -944,7 +962,7 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranches[3], reserveTranches[4], reserveTranches[2]], [toFixedPtAmt("553.710919999999999999"), toFixedPtAmt("500"), toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -952,29 +970,29 @@ describe("PerpetualTranche", function () { }); it("should change reserveCount", async function () { - expect(await perp.callStatic.getReserveCount()).to.eq("4"); + expect(await perp.getReserveCount.staticCall()).to.eq("4"); }); it("should call mature if not already called", async function () { await expect(tx) .to.emit(await bondAt(await reserveTranches[0].bond()), "Mature") - .withArgs(perp.address) + .withArgs(perp.target) .to.emit(await bondAt(await reserveTranches[1].bond()), "Mature") - .withArgs(perp.address); + .withArgs(perp.target); }); it("should emit ReserveSynced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, "553710919999999999999") + .withArgs(collateralToken.target, "553710919999999999999") .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[0].address, "0") + .withArgs(reserveTranches[0].target, "0") .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[1].address, "0"); + .withArgs(reserveTranches[1].target, "0"); }); it("should update the reserve balance", async function () { - expect(await collateralToken.balanceOf(perp.address)).to.eq("553710919999999999999"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("553710919999999999999"); }); }); @@ -986,25 +1004,25 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(0, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); reserveTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -1016,8 +1034,8 @@ describe("PerpetualTranche", function () { toFixedPtAmt("500"), ], ); - expect(await perp.callStatic.getReserveCount()).to.eq("6"); - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); await TimeHelpers.increaseTime(6000); tx = perp.updateState(); @@ -1025,7 +1043,7 @@ describe("PerpetualTranche", function () { }); it("should have expected reserve composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranches[3], reserveTranches[4], reserveTranches[2]], [toFixedPtAmt("1000"), toFixedPtAmt("500"), toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -1033,7 +1051,7 @@ describe("PerpetualTranche", function () { }); it("should change reserveCount", async function () { - expect(await perp.callStatic.getReserveCount()).to.eq("4"); + expect(await perp.getReserveCount.staticCall()).to.eq("4"); }); it("should change mature tranche balances", async function () {}); @@ -1041,23 +1059,23 @@ describe("PerpetualTranche", function () { it("should call mature if not already called", async function () { await expect(tx) .to.emit(await bondAt(await reserveTranches[0].bond()), "Mature") - .withArgs(perp.address) + .withArgs(perp.target) .to.emit(await bondAt(await reserveTranches[1].bond()), "Mature") - .withArgs(perp.address); + .withArgs(perp.target); }); it("should emit ReserveSynced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("1000")) + .withArgs(collateralToken.target, toFixedPtAmt("1000")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[0].address, "0") + .withArgs(reserveTranches[0].target, "0") .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranches[1].address, "0"); + .withArgs(reserveTranches[1].target, "0"); }); it("should update the reserve balance", async function () { - expect(await collateralToken.balanceOf(perp.address)).to.eq(toFixedPtAmt("1000")); + expect(await collateralToken.balanceOf(perp.target)).to.eq(toFixedPtAmt("1000")); }); }); @@ -1069,25 +1087,25 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(0, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); reserveTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -1099,8 +1117,8 @@ describe("PerpetualTranche", function () { toFixedPtAmt("500"), ], ); - expect(await perp.callStatic.getReserveCount()).to.eq("6"); - expect(await collateralToken.balanceOf(perp.address)).to.eq("0"); + expect(await perp.getReserveCount.staticCall()).to.eq("6"); + expect(await collateralToken.balanceOf(perp.target)).to.eq("0"); await TimeHelpers.increaseTime(6000); await perp.updateKeeper(await deployer.getAddress()); @@ -1110,7 +1128,7 @@ describe("PerpetualTranche", function () { }); it("should have not updated composition", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], [ @@ -1133,34 +1151,34 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(600, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); depositTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await advancePerpQueueToRollover(perp, await bondAt(depositTranches[2].bond())); + await advancePerpQueueToRollover(perp, await bondAt(await depositTranches[2].bond())); }); it("should get the rollover ready tranches", async function () { - const r = await perp.callStatic.getReserveTokensUpForRollover(); - expect(r).to.include(collateralToken.address); - expect(r).to.include(depositTranches[2].address); - expect(r).not.to.include(depositTranches[0].address); - expect(r).not.to.include(depositTranches[1].address); - expect(r).not.to.include(depositTranches[3].address); - expect(r).not.to.include(depositTranches[4].address); + const r = await perp.getReserveTokensUpForRollover.staticCall(); + expect(r).to.include(collateralToken.target); + expect(r).to.include(depositTranches[2].target); + expect(r).not.to.include(depositTranches[0].target); + expect(r).not.to.include(depositTranches[1].target); + expect(r).not.to.include(depositTranches[3].target); + expect(r).not.to.include(depositTranches[4].target); }); }); @@ -1171,34 +1189,34 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(600, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); depositTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); } - await advancePerpQueueToRollover(perp, await bondAt(depositTranches[2].bond())); + await advancePerpQueueToRollover(perp, await bondAt(await depositTranches[2].bond())); }); it("should return the token balance", async function () { - expect(await perp.callStatic.getReserveTokenBalance(perp.address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenBalance(collateralToken.address)).to.eq(toFixedPtAmt("1000")); - expect(await perp.callStatic.getReserveTokenBalance(depositTranches[0].address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenBalance(depositTranches[1].address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenBalance(depositTranches[2].address)).to.eq(toFixedPtAmt("500")); - expect(await perp.callStatic.getReserveTokenBalance(depositTranches[3].address)).to.eq(toFixedPtAmt("500")); - expect(await perp.callStatic.getReserveTokenBalance(depositTranches[4].address)).to.eq(toFixedPtAmt("500")); + expect(await perp.getReserveTokenBalance.staticCall(perp.target)).to.eq("0"); + expect(await perp.getReserveTokenBalance.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("1000")); + expect(await perp.getReserveTokenBalance.staticCall(depositTranches[0].target)).to.eq("0"); + expect(await perp.getReserveTokenBalance.staticCall(depositTranches[1].target)).to.eq("0"); + expect(await perp.getReserveTokenBalance.staticCall(depositTranches[2].target)).to.eq(toFixedPtAmt("500")); + expect(await perp.getReserveTokenBalance.staticCall(depositTranches[3].target)).to.eq(toFixedPtAmt("500")); + expect(await perp.getReserveTokenBalance.staticCall(depositTranches[4].target)).to.eq(toFixedPtAmt("500")); }); }); @@ -1209,35 +1227,35 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - await perp.updateBondIssuer(issuer.address); + await perp.updateBondIssuer(issuer.target); await perp.updateTolerableTrancheMaturity(600, 10800); await advancePerpQueue(perp, 10900); for (let i = 0; i < 5; i++) { - const depositBond = await bondAt(await perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const tranches = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(tranches[0].address, toFixedPtAmt("500")); + await tranches[0].approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(tranches[0].target, toFixedPtAmt("500")); depositTranches[i] = tranches[0]; await advancePerpQueue(perp, 1200); await rebase(collateralToken, rebaseOracle, -0.5); } - await advancePerpQueueToRollover(perp, await bondAt(depositTranches[2].bond())); + await advancePerpQueueToRollover(perp, await bondAt(await depositTranches[2].bond())); }); it("should return the tranche value", async function () { - expect(await perp.callStatic.getReserveTokenValue(perp.address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenValue(collateralToken.address)).to.eq(toFixedPtAmt("93.75")); - expect(await perp.callStatic.getReserveTokenValue(depositTranches[0].address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenValue(depositTranches[1].address)).to.eq("0"); - expect(await perp.callStatic.getReserveTokenValue(depositTranches[2].address)).to.eq(toFixedPtAmt("125")); - expect(await perp.callStatic.getReserveTokenValue(depositTranches[3].address)).to.eq(toFixedPtAmt("250")); - expect(await perp.callStatic.getReserveTokenValue(depositTranches[4].address)).to.eq(toFixedPtAmt("500")); + expect(await perp.getReserveTokenValue.staticCall(perp.target)).to.eq("0"); + expect(await perp.getReserveTokenValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("93.75")); + expect(await perp.getReserveTokenValue.staticCall(depositTranches[0].target)).to.eq("0"); + expect(await perp.getReserveTokenValue.staticCall(depositTranches[1].target)).to.eq("0"); + expect(await perp.getReserveTokenValue.staticCall(depositTranches[2].target)).to.eq(toFixedPtAmt("125")); + expect(await perp.getReserveTokenValue.staticCall(depositTranches[3].target)).to.eq(toFixedPtAmt("250")); + expect(await perp.getReserveTokenValue.staticCall(depositTranches[4].target)).to.eq(toFixedPtAmt("500")); }); }); }); diff --git a/spot-contracts/test/perp/PerpetualTranche_deposit.ts b/spot-contracts/test/perp/PerpetualTranche_deposit.ts index d42714e9..3e254598 100644 --- a/spot-contracts/test/perp/PerpetualTranche_deposit.ts +++ b/spot-contracts/test/perp/PerpetualTranche_deposit.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Transaction, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, setupBondFactory, @@ -12,11 +11,11 @@ import { toPercFixedPtAmt, toFixedPtAmt, advancePerpQueue, - checkReserveComposition, + checkPerpComposition, rebase, mintCollteralToken, + DMock, } from "../helpers"; -use(smock.matchers); let perp: Contract, bondFactory: Contract, @@ -43,39 +42,46 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, ); await advancePerpQueue(perp, 3600); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - const vault = await smock.fake(RolloverVault); - await vault.getTVL.returns("0"); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + const vault = new DMock(RolloverVault); + await vault.deploy(); + await vault.mockMethod("getTVL()", [0]); + await perp.updateVault(vault.target); - depositBond = await bondAt(await perp.callStatic.getDepositBond()); + depositBond = await bondAt(await perp.getDepositBond.staticCall()); [depositTrancheA, depositTrancheZ] = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await depositTrancheA.approve(perp.address, toFixedPtAmt("500")); - await depositTrancheZ.approve(perp.address, toFixedPtAmt("500")); - - await feePolicy.computePerpMintFeePerc.returns("0"); + await depositTrancheA.approve(perp.target, toFixedPtAmt("500")); + await depositTrancheZ.approve(perp.target, toFixedPtAmt("500")); }); afterEach(async function () { @@ -90,24 +96,24 @@ describe("PerpetualTranche", function () { }); it("should revert", async function () { - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.revertedWith("Pausable: paused"); + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.revertedWith("Pausable: paused"); }); }); describe("when bond issuer is NOT set correctly", function () { let bond: Contract; beforeEach(async function () { - const BondIssuer = await ethers.getContractFactory("BondIssuer"); - const newIssuer = await smock.fake(BondIssuer); - await newIssuer.collateral.returns(collateralToken.address); - await perp.updateBondIssuer(newIssuer.address); bond = await createBondWithFactory(bondFactory, perp, [200, 300, 500], 3600); - await newIssuer.getLatestBond.returns(bond.address); + const newIssuer = new DMock(await ethers.getContractFactory("BondIssuer")); + await newIssuer.deploy(); + await newIssuer.mockMethod("collateral()", [collateralToken.target]); + await newIssuer.mockMethod("getLatestBond()", [bond.target]); + await perp.updateBondIssuer(newIssuer.target); }); it("should not update the deposit bond", async function () { - await depositTrancheA.approve(perp.address, toFixedPtAmt("500")); - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.not.be.reverted; - expect(await perp.callStatic.getDepositBond()).to.not.eq(bond.address); + await depositTrancheA.approve(perp.target, toFixedPtAmt("500")); + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.not.be.reverted; + expect(await perp.getDepositBond.staticCall()).to.not.eq(bond.target); }); }); @@ -118,8 +124,8 @@ describe("PerpetualTranche", function () { depositTrancheA = (await getTranches(bond))[0]; }); it("should revert", async function () { - await depositTrancheA.approve(perp.address, toFixedPtAmt("500")); - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.revertedWithCustomError( + await depositTrancheA.approve(perp.target, toFixedPtAmt("500")); + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.revertedWithCustomError( perp, "UnexpectedAsset", ); @@ -132,9 +138,9 @@ describe("PerpetualTranche", function () { const maliciousTranche = await ERC20.deploy(); await maliciousTranche.init("Tranche", "TRA"); await maliciousTranche.mint(deployerAddress, toFixedPtAmt("500")); - await maliciousTranche.setBond(await perp.callStatic.getDepositBond()); - await maliciousTranche.approve(perp.address, toFixedPtAmt("500")); - await expect(perp.deposit(maliciousTranche.address, toFixedPtAmt("500"))).to.revertedWithCustomError( + await maliciousTranche.setBond(await perp.getDepositBond.staticCall()); + await maliciousTranche.approve(perp.target, toFixedPtAmt("500")); + await expect(perp.deposit(maliciousTranche.target, toFixedPtAmt("500"))).to.revertedWithCustomError( perp, "UnexpectedAsset", ); @@ -143,10 +149,10 @@ describe("PerpetualTranche", function () { describe("when user has not approved sufficient tranche tokens", function () { beforeEach(async function () { - await depositTrancheA.approve(perp.address, "0"); + await depositTrancheA.approve(perp.target, "0"); }); it("should revert", async function () { - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.revertedWith( + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.revertedWith( "ERC20: transfer amount exceeds allowance", ); }); @@ -154,11 +160,11 @@ describe("PerpetualTranche", function () { describe("when user has insufficient balance", function () { beforeEach(async function () { - await depositTrancheA.transfer(perp.address, toFixedPtAmt("500")); + await depositTrancheA.transfer(perp.target, toFixedPtAmt("500")); }); it("should revert", async function () { expect(await depositTrancheA.balanceOf(deployerAddress)).to.eq("0"); - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.revertedWith( + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.revertedWith( "ERC20: transfer amount exceeds balance", ); }); @@ -170,7 +176,7 @@ describe("PerpetualTranche", function () { }); it("should revert", async function () { - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.revertedWithCustomError( + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.revertedWithCustomError( perp, "ExceededMaxSupply", ); @@ -179,12 +185,12 @@ describe("PerpetualTranche", function () { describe("when the supply cap is exceeded and existing supply > 0", function () { beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("400")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("400")); await perp.updateMaxSupply(toFixedPtAmt("499")); }); it("should revert", async function () { - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("100"))).to.revertedWithCustomError( + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("100"))).to.revertedWithCustomError( perp, "ExceededMaxSupply", ); @@ -196,7 +202,7 @@ describe("PerpetualTranche", function () { await perp.updateMaxDepositTrancheValuePerc(toPercFixedPtAmt("0.5")); }); it("should not revert", async function () { - await expect(perp.deposit(depositTrancheA.address, toFixedPtAmt("100"))).to.revertedWithCustomError( + await expect(perp.deposit(depositTrancheA.target, toFixedPtAmt("100"))).to.revertedWithCustomError( perp, "ExceededMaxMintPerTranche", ); @@ -205,59 +211,62 @@ describe("PerpetualTranche", function () { describe("when the tranche mint limit has not exceeded and existing supply > 0", function () { beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("250")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("250")); await advancePerpQueue(perp, 1200); + await perp.updateTolerableTrancheMaturity(1, ethers.MaxUint256); await perp.updateMaxDepositTrancheValuePerc(toPercFixedPtAmt("0.5")); }); it("should NOT revert", async function () { await mintCollteralToken(collateralToken, toFixedPtAmt("50"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("10")); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + await collateralToken.transfer(perp.target, toFixedPtAmt("10")); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("2000"), deployer); const tranches = await getTranches(newBond); const newTranche = tranches[0]; - await newTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newTranche.address, toFixedPtAmt("200")); - await expect(perp.deposit(newTranche.address, toFixedPtAmt("1"))).not.to.reverted; + await newTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newTranche.target, toFixedPtAmt("200")); + await expect(perp.deposit(newTranche.target, toFixedPtAmt("1"))).not.to.reverted; }); }); describe("when the tranche mint limit has exceeded and existing supply > 0", function () { beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("250")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("250")); await advancePerpQueue(perp, 1200); + await perp.updateTolerableTrancheMaturity(1, ethers.MaxUint256); await perp.updateMaxDepositTrancheValuePerc(toPercFixedPtAmt("0.5")); }); it("should revert", async function () { await mintCollteralToken(collateralToken, toFixedPtAmt("50"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("50")); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + await collateralToken.transfer(perp.target, toFixedPtAmt("50")); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("2000"), deployer); const tranches = await getTranches(newBond); const newTranche = tranches[0]; - await newTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newTranche.address, toFixedPtAmt("200")); - await expect(perp.deposit(newTranche.address, toFixedPtAmt("1"))).to.reverted; + await newTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newTranche.target, toFixedPtAmt("200")); + await expect(perp.deposit(newTranche.target, toFixedPtAmt("1"))).to.reverted; }); }); describe("when the tranche mint limit is exceeded and existing supply > 0", function () { beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("250")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("250")); await advancePerpQueue(perp, 1200); + await perp.updateTolerableTrancheMaturity(1, ethers.MaxUint256); await perp.updateMaxDepositTrancheValuePerc(toPercFixedPtAmt("0.5")); }); it("should revert", async function () { - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("2000"), deployer); const tranches = await getTranches(newBond); const newTranche = tranches[0]; - await newTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newTranche.address, toFixedPtAmt("250")); - await expect(perp.deposit(newTranche.address, toFixedPtAmt("1"))).to.revertedWithCustomError( + await newTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newTranche.target, toFixedPtAmt("250")); + await expect(perp.deposit(newTranche.target, toFixedPtAmt("1"))).to.revertedWithCustomError( perp, "ExceededMaxMintPerTranche", ); @@ -266,13 +275,13 @@ describe("PerpetualTranche", function () { describe("when tranche amount is zero", function () { it("should return without minting", async function () { - expect(await perp.callStatic.deposit(depositTrancheA.address, "0")).to.eq("0"); + expect(await perp.deposit.staticCall(depositTrancheA.target, "0")).to.eq("0"); }); }); describe("when depositing a junior", function () { it("should return without minting", async function () { - await expect(perp.deposit(depositTrancheZ.address, toFixedPtAmt("500"))).to.revertedWithCustomError( + await expect(perp.deposit(depositTrancheZ.target, toFixedPtAmt("500"))).to.revertedWithCustomError( perp, "UnexpectedAsset", ); @@ -282,7 +291,7 @@ describe("PerpetualTranche", function () { describe("when total supply is zero", function () { describe("when tranche price is 1", function () { it("should mint the correct amount", async function () { - const r = await perp.callStatic.computeMintAmt(depositTrancheA.address, toFixedPtAmt("500")); + const r = await perp.computeMintAmt.staticCall(depositTrancheA.target, toFixedPtAmt("500")); expect(r).to.eq(toFixedPtAmt("500")); }); }); @@ -293,7 +302,7 @@ describe("PerpetualTranche", function () { }); it("should mint the correct amount", async function () { - const r = await perp.callStatic.computeMintAmt(depositTrancheA.address, toFixedPtAmt("500")); + const r = await perp.computeMintAmt.staticCall(depositTrancheA.target, toFixedPtAmt("500")); expect(r).to.eq(toFixedPtAmt("250")); }); }); @@ -302,19 +311,19 @@ describe("PerpetualTranche", function () { describe("when total supply > zero", function () { let newBond: Contract, newTranche: Contract; beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("200")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("200")); await advancePerpQueue(perp, 1200); - newBond = await bondAt(await perp.callStatic.getDepositBond()); + newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newTranche = tranches[0]; - await newTranche.approve(perp.address, toFixedPtAmt("250")); + await newTranche.approve(perp.target, toFixedPtAmt("250")); }); describe("when price is eql to avg reserve price", function () { it("should mint the correct amount", async function () { - const r = await perp.callStatic.computeMintAmt(newTranche.address, toFixedPtAmt("250")); + const r = await perp.computeMintAmt.staticCall(newTranche.target, toFixedPtAmt("250")); expect(r).to.eq(toFixedPtAmt("250")); }); }); @@ -322,11 +331,11 @@ describe("PerpetualTranche", function () { describe("when price is < avg reserve price", function () { beforeEach(async function () { await mintCollteralToken(collateralToken, toFixedPtAmt("500"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("200")); + await collateralToken.transfer(perp.target, toFixedPtAmt("200")); }); it("should mint the correct amount", async function () { - const r = await perp.callStatic.computeMintAmt(newTranche.address, toFixedPtAmt("250")); + const r = await perp.computeMintAmt.staticCall(newTranche.target, toFixedPtAmt("250")); expect(r).to.eq(toFixedPtAmt("125")); }); }); @@ -336,15 +345,15 @@ describe("PerpetualTranche", function () { await rebase(collateralToken, rebaseOracle, -0.75); await advancePerpQueue(perp, 1200); - newBond = await bondAt(await perp.callStatic.getDepositBond()); + newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newTranche = tranches[0]; - await newTranche.approve(perp.address, toFixedPtAmt("250")); + await newTranche.approve(perp.target, toFixedPtAmt("250")); }); it("should mint the correct amount", async function () { - const r = await perp.callStatic.computeMintAmt(newTranche.address, toFixedPtAmt("250")); + const r = await perp.computeMintAmt.staticCall(newTranche.target, toFixedPtAmt("250")); expect(r).to.eq(toFixedPtAmt("500")); }); }); @@ -352,28 +361,28 @@ describe("PerpetualTranche", function () { describe("on successful deposit", function () { it("should mint perp tokens", async function () { - await expect(() => perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.changeTokenBalance( + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalance( perp, deployer, toFixedPtAmt("500"), ); }); it("should NOT withhold any fee amount", async function () { - await expect(() => perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.changeTokenBalance( + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalance( perp, perp, "0", ); }); it("should transfer the tranches in", async function () { - await expect(() => perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.changeTokenBalances( + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalances( depositTrancheA, [deployer, perp], [toFixedPtAmt("-500"), toFixedPtAmt("500")], ); }); it("should return the mintAmt", async function () { - const r = await perp.callStatic.computeMintAmt(depositTrancheA.address, toFixedPtAmt("500")); + const r = await perp.computeMintAmt.staticCall(depositTrancheA.target, toFixedPtAmt("500")); expect(r).to.eq(toFixedPtAmt("500")); }); }); @@ -381,24 +390,24 @@ describe("PerpetualTranche", function () { describe("when the reserve has no tranches", function () { let tx: Transaction; beforeEach(async function () { - expect(await perp.callStatic.getDepositBond()).to.eq(depositBond.address); + expect(await perp.getDepositBond.staticCall()).to.eq(depositBond.target); - await checkReserveComposition(perp, [collateralToken], ["0"]); + await checkPerpComposition(perp, [collateralToken], ["0"]); expect(await perp.totalSupply()).to.eq(0); - tx = perp.deposit(depositTrancheA.address, toFixedPtAmt("500")); + tx = perp.deposit(depositTrancheA.target, toFixedPtAmt("500")); await tx; }); it("should NOT update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.eq(depositBond.address); + expect(await perp.getDepositBond.staticCall()).to.eq(depositBond.target); }); it("should emit reserve synced", async function () { - await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTrancheA.address, toFixedPtAmt("500")); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTrancheA.target, toFixedPtAmt("500")); }); it("should update the reserve", async function () { - await checkReserveComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("500")]); }); it("should update the total supply", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("500")); @@ -407,10 +416,10 @@ describe("PerpetualTranche", function () { describe("when the reserve has tranches", function () { beforeEach(async function () { - await perp.deposit(depositTrancheA.address, toFixedPtAmt("200")); + await perp.deposit(depositTrancheA.target, toFixedPtAmt("200")); - expect(await perp.callStatic.getDepositBond()).to.eq(depositBond.address); - await checkReserveComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("200")]); + expect(await perp.getDepositBond.staticCall()).to.eq(depositBond.target); + await checkPerpComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("200")]); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("200")); }); @@ -418,18 +427,18 @@ describe("PerpetualTranche", function () { describe("when inserting the an existing tranche", async function () { let tx: Transaction; beforeEach(async function () { - tx = perp.deposit(depositTrancheA.address, toFixedPtAmt("300")); + tx = perp.deposit(depositTrancheA.target, toFixedPtAmt("300")); await tx; }); it("should NOT update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.eq(depositBond.address); + expect(await perp.getDepositBond.staticCall()).to.eq(depositBond.target); }); it("should emit reserve synced", async function () { - await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTrancheA.address, toFixedPtAmt("500")); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTrancheA.target, toFixedPtAmt("500")); }); it("should update the reserve", async function () { - await checkReserveComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("500")]); }); it("should update the total supply", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("500")); @@ -441,25 +450,25 @@ describe("PerpetualTranche", function () { beforeEach(async function () { await advancePerpQueue(perp, 1200); - newBond = await bondAt(await perp.callStatic.getDepositBond()); + newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newTranche = tranches[0]; - await checkReserveComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("200")]); + await checkPerpComposition(perp, [collateralToken, depositTrancheA], ["0", toFixedPtAmt("200")]); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("200")); - await newTranche.approve(perp.address, toFixedPtAmt("250")); - tx = perp.deposit(newTranche.address, toFixedPtAmt("250")); + await newTranche.approve(perp.target, toFixedPtAmt("250")); + tx = perp.deposit(newTranche.target, toFixedPtAmt("250")); await tx; }); it("should update the deposit bond", async function () { - expect(await perp.callStatic.getDepositBond()).to.eq(newBond.address); + expect(await perp.getDepositBond.staticCall()).to.eq(newBond.target); }); it("should emit reserve synced", async function () { - await expect(tx).to.emit(perp, "ReserveSynced").withArgs(newTranche.address, toFixedPtAmt("250")); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(newTranche.target, toFixedPtAmt("250")); }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, depositTrancheA, newTranche], ["0", toFixedPtAmt("200"), toFixedPtAmt("250")], @@ -473,26 +482,50 @@ describe("PerpetualTranche", function () { describe("when fee is set", function () { beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.01")); + await feePolicy.clearMockMethod("computeDeviationRatio((uint256,uint256,uint256))"); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("0"), toFixedPtAmt("0"), "500"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("500"), toFixedPtAmt("0"), "500"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.01")]); }); it("should mint perp tokens", async function () { - await expect(() => perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.changeTokenBalance( + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalance( perp, deployer, toFixedPtAmt("495"), ); }); it("should transfer the tranches in", async function () { - await expect(() => perp.deposit(depositTrancheA.address, toFixedPtAmt("500"))).to.changeTokenBalances( + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalances( depositTrancheA, [deployer, perp], [toFixedPtAmt("-500"), toFixedPtAmt("500")], ); }); it("should return the mintAmt", async function () { - const r = await perp.callStatic.computeMintAmt(depositTrancheA.address, toFixedPtAmt("500")); + const r = await perp.computeMintAmt.staticCall(depositTrancheA.target, toFixedPtAmt("500")); expect(r).to.eq(toFixedPtAmt("495")); }); + + it("should update the total supply", async function () { + await perp.deposit(depositTrancheA.target, toFixedPtAmt("500")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("500")); + }); + + it("should mint fees to perp", async function () { + await expect(() => perp.deposit(depositTrancheA.target, toFixedPtAmt("500"))).to.changeTokenBalances( + perp, + [perp], + [toFixedPtAmt("5")], + ); + }); }); describe("when fee is set and caller is the vault", function () { @@ -500,24 +533,24 @@ describe("PerpetualTranche", function () { beforeEach(async function () { const MockVault = await ethers.getContractFactory("MockVault"); mockVault = await MockVault.deploy(); - await perp.updateVault(mockVault.address); - await depositTrancheA.approve(mockVault.address, toFixedPtAmt("500")); - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("1")); + await perp.updateVault(mockVault.target); + await depositTrancheA.approve(mockVault.target, toFixedPtAmt("500")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("11")]); }); it("should mint perp tokens", async function () { await expect(() => - mockVault.mintPerps(perp.address, depositTrancheA.address, toFixedPtAmt("500")), + mockVault.mintPerps(perp.target, depositTrancheA.target, toFixedPtAmt("500")), ).to.changeTokenBalance(perp, deployer, toFixedPtAmt("500")); }); it("should transfer the tranches in", async function () { await expect(() => - mockVault.mintPerps(perp.address, depositTrancheA.address, toFixedPtAmt("500")), + mockVault.mintPerps(perp.target, depositTrancheA.target, toFixedPtAmt("500")), ).to.changeTokenBalances(depositTrancheA, [deployer, perp], [toFixedPtAmt("-500"), toFixedPtAmt("500")]); }); it("should return the mintAmt", async function () { - const r = await mockVault.callStatic.computePerpMintAmt( - perp.address, - depositTrancheA.address, + const r = await mockVault.computePerpMintAmt.staticCall( + perp.target, + depositTrancheA.target, toFixedPtAmt("500"), ); expect(r).to.eq(toFixedPtAmt("500")); diff --git a/spot-contracts/test/perp/PerpetualTranche_redeem.ts b/spot-contracts/test/perp/PerpetualTranche_redeem.ts index 61291431..f0f3d04f 100644 --- a/spot-contracts/test/perp/PerpetualTranche_redeem.ts +++ b/spot-contracts/test/perp/PerpetualTranche_redeem.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Transaction, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, setupBondFactory, @@ -11,11 +10,11 @@ import { toPercFixedPtAmt, toFixedPtAmt, advancePerpQueue, - checkReserveComposition, + checkPerpComposition, rebase, mintCollteralToken, + DMock, } from "../helpers"; -use(smock.matchers); let perp: Contract, bondFactory: Contract, @@ -44,38 +43,46 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 3600, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 3600, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, ); await advancePerpQueue(perp, 3600); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - const vault = await smock.fake(RolloverVault); - await vault.getTVL.returns("0"); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + const vault = new DMock(RolloverVault); + await vault.deploy(); + await vault.mockMethod("getTVL()", [0]); + await perp.updateVault(vault.target); - depositBond = await bondAt(await perp.callStatic.getDepositBond()); + depositBond = await bondAt(await perp.getDepositBond.staticCall()); [initialDepositTranche] = await getTranches(depositBond); await depositIntoBond(depositBond, toFixedPtAmt("1000"), deployer); - await initialDepositTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(initialDepositTranche.address, toFixedPtAmt("500")); - await feePolicy.computePerpBurnFeePerc.returns("0"); + await initialDepositTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(initialDepositTranche.target, toFixedPtAmt("500")); await mintCollteralToken(collateralToken, toFixedPtAmt("1000"), deployer); }); @@ -85,23 +92,23 @@ describe("PerpetualTranche", function () { describe("#burn", function () { it("should burn tokens without redemption", async function () { - await checkReserveComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); expect(await perp.balanceOf(deployerAddress)).to.eq(toFixedPtAmt("500")); await perp.burn(toFixedPtAmt("500")); expect(await perp.balanceOf(deployerAddress)).to.eq("0"); - await checkReserveComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); }); }); describe("#burnFrom", function () { it("should burn tokens without redemption from authorized wallet", async function () { - await checkReserveComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); expect(await perp.balanceOf(deployerAddress)).to.eq(toFixedPtAmt("500")); await perp.approve(await otherUser.getAddress(), toFixedPtAmt("500")); await perp.connect(otherUser).burnFrom(deployerAddress, toFixedPtAmt("200")); expect(await perp.balanceOf(deployerAddress)).to.eq(toFixedPtAmt("300")); expect(await perp.allowance(deployerAddress, await otherUser.getAddress())).to.eq(toFixedPtAmt("300")); - await checkReserveComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); + await checkPerpComposition(perp, [collateralToken, initialDepositTranche], ["0", toFixedPtAmt("500")]); }); }); @@ -130,7 +137,7 @@ describe("PerpetualTranche", function () { describe("when requested amount is zero", function () { it("should return without redeeming", async function () { - expect(await perp.callStatic.redeem("0")).to.deep.eq([]); + expect(await perp.redeem.staticCall("0")).to.deep.eq([]); }); }); @@ -144,7 +151,7 @@ describe("PerpetualTranche", function () { }); it("should revert", async function () { - await expect(perp.callStatic.computeRedemptionAmts(toFixedPtAmt("100"))).to.be.reverted; + await expect(perp.computeRedemptionAmts.staticCall(toFixedPtAmt("100"))).to.be.reverted; }); }); @@ -166,21 +173,21 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(perp.redeem(toFixedPtAmt("500"))) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, "0") + .withArgs(collateralToken.target, "0") .to.emit(perp, "ReserveSynced") - .withArgs(initialDepositTranche.address, "0"); + .withArgs(initialDepositTranche.target, "0"); }); it("should return the redemption amounts", async function () { - const r = await perp.callStatic.redeem(toFixedPtAmt("500")); - expect(r[0].token).to.eq(collateralToken.address); - expect(r[1].token).to.eq(initialDepositTranche.address); + const r = await perp.redeem.staticCall(toFixedPtAmt("500")); + expect(r[0].token).to.eq(collateralToken.target); + expect(r[1].token).to.eq(initialDepositTranche.target); expect(r[0].amount).to.eq("0"); expect(r[1].amount).to.eq(toFixedPtAmt("500")); }); it("should return the redemption amounts", async function () { - const r = await perp.callStatic.computeRedemptionAmts(toFixedPtAmt("500")); - expect(r[0].token).to.eq(collateralToken.address); - expect(r[1].token).to.eq(initialDepositTranche.address); + const r = await perp.computeRedemptionAmts.staticCall(toFixedPtAmt("500")); + expect(r[0].token).to.eq(collateralToken.target); + expect(r[1].token).to.eq(initialDepositTranche.target); expect(r[0].amount).to.eq("0"); expect(r[1].amount).to.eq(toFixedPtAmt("500")); }); @@ -193,15 +200,15 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -213,7 +220,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("312.5"), toFixedPtAmt("312.5")], @@ -256,16 +263,16 @@ describe("PerpetualTranche", function () { await perp.updateTolerableTrancheMaturity(1200, 3600); await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await collateralToken.transfer(perp.address, toFixedPtAmt("100")); - await checkReserveComposition( + await collateralToken.transfer(perp.target, toFixedPtAmt("100")); + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("100"), toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -277,7 +284,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("50"), toFixedPtAmt("250"), toFixedPtAmt("250")], @@ -324,15 +331,15 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -340,7 +347,7 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 2400); await rebase(collateralToken, rebaseOracle, +0.5); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newRedemptionTranche], [toFixedPtAmt("750"), toFixedPtAmt("500")], @@ -352,7 +359,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newRedemptionTranche], [toFixedPtAmt("468.75"), toFixedPtAmt("312.5")], @@ -388,15 +395,15 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -404,7 +411,7 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 2400); await rebase(collateralToken, rebaseOracle, -0.5); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newRedemptionTranche], [toFixedPtAmt("250"), toFixedPtAmt("500")], @@ -416,7 +423,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newRedemptionTranche], [toFixedPtAmt("156.25"), toFixedPtAmt("312.5")], @@ -448,22 +455,22 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("500")], ); await advancePerpQueue(perp, 7200); - await checkReserveComposition(perp, [collateralToken], [toFixedPtAmt("1000")]); + await checkPerpComposition(perp, [collateralToken], [toFixedPtAmt("1000")]); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("1000")); txFn = () => perp.redeem(toFixedPtAmt("375")); @@ -471,7 +478,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition(perp, [collateralToken], [toFixedPtAmt("625")]); + await checkPerpComposition(perp, [collateralToken], [toFixedPtAmt("625")]); }); it("should transfer tokens out", async function () { @@ -499,15 +506,15 @@ describe("PerpetualTranche", function () { await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("500")], @@ -520,7 +527,7 @@ describe("PerpetualTranche", function () { it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition(perp, [collateralToken], ["0"]); + await checkPerpComposition(perp, [collateralToken], ["0"]); }); it("should transfer tokens out", async function () { @@ -559,29 +566,40 @@ describe("PerpetualTranche", function () { await perp.updateTolerableTrancheMaturity(1200, 3600); await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await collateralToken.transfer(perp.address, toFixedPtAmt("100")); - await checkReserveComposition( + await collateralToken.transfer(perp.target, toFixedPtAmt("100")); + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("100"), toFixedPtAmt("500"), toFixedPtAmt("500")], ); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("1000")); - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.clearMockMethod("computeDeviationRatio((uint256,uint256,uint256))"); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("1100"), toFixedPtAmt("0"), "500"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("550"), toFixedPtAmt("0"), "500"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); txFn = () => perp.redeem(toFixedPtAmt("500")); }); it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("55"), toFixedPtAmt("275"), toFixedPtAmt("275")], @@ -614,12 +632,16 @@ describe("PerpetualTranche", function () { it("should update the total supply", async function () { await txFn(); - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("500")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("550")); }); it("should burn perp tokens", async function () { await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("-500")]); }); + + it("should mint fees to perp", async function () { + await expect(txFn).to.changeTokenBalances(perp, [perp], [toFixedPtAmt("50")]); + }); }); describe("when fee is set and caller is vault", function () { @@ -628,33 +650,33 @@ describe("PerpetualTranche", function () { await perp.updateTolerableTrancheMaturity(1200, 3600); await advancePerpQueue(perp, 1200); - const newBond = await bondAt(await perp.callStatic.getDepositBond()); + const newBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newBond, toFixedPtAmt("1000"), deployer); const tranches = await getTranches(newBond); newRedemptionTranche = tranches[0]; - await newRedemptionTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(newRedemptionTranche.address, toFixedPtAmt("500")); + await newRedemptionTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(newRedemptionTranche.target, toFixedPtAmt("500")); - await collateralToken.transfer(perp.address, toFixedPtAmt("100")); - await checkReserveComposition( + await collateralToken.transfer(perp.target, toFixedPtAmt("100")); + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("100"), toFixedPtAmt("500"), toFixedPtAmt("500")], ); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("1000")); - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("1")]); const MockVault = await ethers.getContractFactory("MockVault"); mockVault = await MockVault.deploy(); - await perp.updateVault(mockVault.address); - await perp.approve(mockVault.address, toFixedPtAmt("500")); - txFn = () => mockVault.redeemPerps(perp.address, toFixedPtAmt("500")); + await perp.updateVault(mockVault.target); + await perp.approve(mockVault.target, toFixedPtAmt("500")); + txFn = () => mockVault.redeemPerps(perp.target, toFixedPtAmt("500")); }); it("should update the reserve composition", async function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, initialDepositTranche, newRedemptionTranche], [toFixedPtAmt("50"), toFixedPtAmt("250"), toFixedPtAmt("250")], @@ -695,10 +717,10 @@ describe("PerpetualTranche", function () { }); it("should return the redemption amounts", async function () { - const r = await mockVault.callStatic.computePerpRedemptionAmts(perp.address, toFixedPtAmt("500")); - expect(r[0].token).to.eq(collateralToken.address); - expect(r[1].token).to.eq(initialDepositTranche.address); - expect(r[2].token).to.eq(newRedemptionTranche.address); + const r = await mockVault.computePerpRedemptionAmts.staticCall(perp.target, toFixedPtAmt("500")); + expect(r[0].token).to.eq(collateralToken.target); + expect(r[1].token).to.eq(initialDepositTranche.target); + expect(r[2].token).to.eq(newRedemptionTranche.target); expect(r[0].amount).to.eq(toFixedPtAmt("50")); expect(r[1].amount).to.eq(toFixedPtAmt("250")); expect(r[2].amount).to.eq(toFixedPtAmt("250")); diff --git a/spot-contracts/test/perp/PerpetualTranche_rollover.ts b/spot-contracts/test/perp/PerpetualTranche_rollover.ts index c6a2787d..efb244c1 100644 --- a/spot-contracts/test/perp/PerpetualTranche_rollover.ts +++ b/spot-contracts/test/perp/PerpetualTranche_rollover.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Transaction, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, setupBondFactory, @@ -14,11 +13,11 @@ import { advancePerpQueue, advancePerpQueueToBondMaturity, advancePerpQueueToRollover, - checkReserveComposition, + checkPerpComposition, rebase, mintCollteralToken, + DMock, } from "../helpers"; -use(smock.matchers); let perp: Contract, bondFactory: Contract, @@ -50,15 +49,17 @@ describe("PerpetualTranche", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 10800, [500, 500], 1200, 0], + [bondFactory.target, collateralToken.target, 10800, [500, 500], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const MockVault = await ethers.getContractFactory("MockVault"); mockVault = await MockVault.deploy(); @@ -66,7 +67,7 @@ describe("PerpetualTranche", function () { const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -74,42 +75,42 @@ describe("PerpetualTranche", function () { await perp.updateTolerableTrancheMaturity(1200, 10800); await advancePerpQueue(perp, 10900); - await perp.updateVault(mockVault.address); + await perp.updateVault(mockVault.target); - holdingPenBond = await bondAt(await perp.callStatic.getDepositBond()); + holdingPenBond = await bondAt(await perp.getDepositBond.staticCall()); [holdingPenTranche1] = await getTranches(holdingPenBond); await depositIntoBond(holdingPenBond, toFixedPtAmt("2000"), deployer); - await holdingPenTranche1.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(holdingPenTranche1.address, toFixedPtAmt("500")); + await holdingPenTranche1.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(holdingPenTranche1.target, toFixedPtAmt("500")); await advancePerpQueue(perp, 1200); - reserveBond = await bondAt(await perp.callStatic.getDepositBond()); + reserveBond = await bondAt(await perp.getDepositBond.staticCall()); [reserveTranche] = await getTranches(reserveBond); await depositIntoBond(reserveBond, toFixedPtAmt("2000"), deployer); - await reserveTranche.approve(perp.address, toFixedPtAmt("500")); - await perp.deposit(reserveTranche.address, toFixedPtAmt("500")); + await reserveTranche.approve(perp.target, toFixedPtAmt("500")); + await perp.deposit(reserveTranche.target, toFixedPtAmt("500")); await advancePerpQueueToBondMaturity(perp, holdingPenBond); - rolloverInBond = await bondAt(await perp.callStatic.getDepositBond()); + rolloverInBond = await bondAt(await perp.getDepositBond.staticCall()); [rolloverInTranche] = await getTranches(rolloverInBond); await depositIntoBond(rolloverInBond, toFixedPtAmt("5000"), deployer); - await rolloverInTranche.approve(perp.address, toFixedPtAmt("5000")); - await perp.deposit(rolloverInTranche.address, toFixedPtAmt("500")); + await rolloverInTranche.approve(perp.target, toFixedPtAmt("5000")); + await perp.deposit(rolloverInTranche.target, toFixedPtAmt("500")); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("500"), toFixedPtAmt("500")], ); - await rolloverInTranche.approve(mockVault.address, toFixedPtAmt("5000")); - await reserveTranche.approve(mockVault.address, toFixedPtAmt("5000")); + await rolloverInTranche.approve(mockVault.target, toFixedPtAmt("5000")); + await reserveTranche.approve(mockVault.target, toFixedPtAmt("5000")); }); afterEach(async function () { @@ -125,26 +126,26 @@ describe("PerpetualTranche", function () { it("should revert", async function () { await expect( - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWith("Pausable: paused"); }); }); describe("when rollover vault reference is set", function () { beforeEach(async function () { - await perp.updateVault(mockVault.address); + await perp.updateVault(mockVault.target); }); it("should revert when invoked from other addresses", async function () { await expect( - perp.rollover(rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + perp.rollover(rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnauthorizedCall"); }); it("should NOT revert when invoked from the vault ", async function () { - await rolloverInTranche.approve(mockVault.address, toFixedPtAmt("500")); + await rolloverInTranche.approve(mockVault.target, toFixedPtAmt("500")); await expect( - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).not.to.be.reverted; }); }); @@ -156,7 +157,7 @@ describe("PerpetualTranche", function () { }); it("should revert", async function () { await expect( - mockVault.rollover(perp.address, rolloverInTranche.address, tranches[1].address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, tranches[1].target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -164,16 +165,16 @@ describe("PerpetualTranche", function () { describe("when trancheIn is NOT of deposit bond", function () { it("should revert", async function () { await expect( - mockVault.rollover(perp.address, reserveTranche.address, collateralToken.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, reserveTranche.target, collateralToken.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); await expect( - mockVault.rollover(perp.address, reserveTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, reserveTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); await expect( - mockVault.rollover(perp.address, reserveTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, reserveTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); await expect( - mockVault.rollover(perp.address, reserveTranche.address, holdingPenTranche1.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, reserveTranche.target, holdingPenTranche1.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -186,7 +187,7 @@ describe("PerpetualTranche", function () { }); it("should revert", async function () { await expect( - mockVault.rollover(perp.address, rolloverInTranche.address, maliciousTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, maliciousTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -195,19 +196,14 @@ describe("PerpetualTranche", function () { let newRotationInTranche: Contract; beforeEach(async function () { await advancePerpQueue(perp, 1200); - const newRotationInBond = await bondAt(await perp.callStatic.getDepositBond()); + const newRotationInBond = await bondAt(await perp.getDepositBond.staticCall()); [newRotationInTranche] = await getTranches(newRotationInBond); await depositIntoBond(newRotationInBond, toFixedPtAmt("2000"), deployer); - await newRotationInTranche.approve(mockVault.address, toFixedPtAmt("500")); + await newRotationInTranche.approve(mockVault.target, toFixedPtAmt("500")); }); it("should revert", async function () { await expect( - mockVault.rollover( - perp.address, - newRotationInTranche.address, - rolloverInTranche.address, - toFixedPtAmt("500"), - ), + mockVault.rollover(perp.target, newRotationInTranche.target, rolloverInTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -219,12 +215,12 @@ describe("PerpetualTranche", function () { maliciousTranche = await ERC20.deploy(); await maliciousTranche.init("Tranche", "TRA"); await maliciousTranche.mint(deployerAddress, toFixedPtAmt("500")); - await maliciousTranche.setBond(await perp.callStatic.getDepositBond()); - await maliciousTranche.approve(mockVault.address, toFixedPtAmt("500")); + await maliciousTranche.setBond(await perp.getDepositBond.staticCall()); + await maliciousTranche.approve(mockVault.target, toFixedPtAmt("500")); }); it("should revert", async function () { await expect( - mockVault.rollover(perp.address, maliciousTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, maliciousTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -237,26 +233,26 @@ describe("PerpetualTranche", function () { it("should revert", async function () { expect(await rolloverInTranche.balanceOf(deployerAddress)).to.lt(toFixedPtAmt("500")); await expect( - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWith("ERC20: transfer amount exceeds balance"); }); }); describe("when approval is insufficient", function () { it("should return without rollover", async function () { - await rolloverInTranche.transfer(mockVault.address, toFixedPtAmt("500")); + await rolloverInTranche.transfer(mockVault.target, toFixedPtAmt("500")); await expect( - mockVault.callRollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.callRollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWith("ERC20: transfer amount exceeds allowance"); }); }); describe("when trancheInAmt is zero", function () { it("should return without rollover", async function () { - const r = await mockVault.callStatic.rollover( - perp.address, - rolloverInTranche.address, - reserveTranche.address, + const r = await mockVault.rollover.staticCall( + perp.target, + rolloverInTranche.target, + reserveTranche.target, "0", ); expect(r.tokenOutAmt).to.eq("0"); @@ -269,12 +265,12 @@ describe("PerpetualTranche", function () { beforeEach(async function () { const tranches = await getTranches(rolloverInBond); newRotationInTranche = tranches[1]; - await newRotationInTranche.approve(mockVault.address, toFixedPtAmt("500")); + await newRotationInTranche.approve(mockVault.target, toFixedPtAmt("500")); }); it("should revert", async function () { await expect( - mockVault.rollover(perp.address, newRotationInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, newRotationInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.revertedWithCustomError(perp, "UnacceptableRollover"); }); }); @@ -283,13 +279,13 @@ describe("PerpetualTranche", function () { beforeEach(async function () { await rebase(collateralToken, rebaseOracle, -0.75); await mintCollteralToken(collateralToken, toFixedPtAmt("1000"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("1000")); + await collateralToken.transfer(perp.target, toFixedPtAmt("1000")); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -304,14 +300,14 @@ describe("PerpetualTranche", function () { await advancePerpQueueToRollover(perp, await bondAt(await rolloverInTranche.bond())); newReserveTranche = rolloverInTranche; - const newDepositBond = await bondAt(await perp.callStatic.getDepositBond()); + const newDepositBond = await bondAt(await perp.getDepositBond.staticCall()); [newRotationInTranche] = await getTranches(newDepositBond); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - newRotationInTranche.address, - newReserveTranche.address, + const r = await perp.computeRolloverAmt.staticCall( + newRotationInTranche.target, + newReserveTranche.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -325,9 +321,9 @@ describe("PerpetualTranche", function () { }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -341,9 +337,9 @@ describe("PerpetualTranche", function () { }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -356,13 +352,13 @@ describe("PerpetualTranche", function () { await rebase(collateralToken, rebaseOracle, -0.75); // simulating collateral rebase up, by just transferring some tokens in await mintCollteralToken(collateralToken, toFixedPtAmt("1000"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("1000")); + await collateralToken.transfer(perp.target, toFixedPtAmt("1000")); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -373,14 +369,14 @@ describe("PerpetualTranche", function () { describe("when trancheIn price is 0.5 and tokenOut is collateral which rebased down", function () { beforeEach(async function () { await mintCollteralToken(collateralToken, toFixedPtAmt("1000"), deployer); - await collateralToken.transfer(perp.address, toFixedPtAmt("1000")); + await collateralToken.transfer(perp.target, toFixedPtAmt("1000")); await rebase(collateralToken, rebaseOracle, -0.75); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -393,9 +389,9 @@ describe("PerpetualTranche", function () { await rebase(collateralToken, rebaseOracle, -0.25); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("375")); @@ -408,9 +404,9 @@ describe("PerpetualTranche", function () { await rebase(collateralToken, rebaseOracle, 0.25); }); it("should rollover the correct amount", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -418,29 +414,27 @@ describe("PerpetualTranche", function () { }); }); - describe("when fee is zero", function () { - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns("0"); - }); + describe("when typical rollover", function () { + beforeEach(async function () {}); it("should transfer the tranches in", async function () { await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.changeTokenBalances(rolloverInTranche, [deployer, perp], [toFixedPtAmt("-500"), toFixedPtAmt("500")]); }); it("should transfer the tranches out", async function () { await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.changeTokenBalances(reserveTranche, [deployer, perp], [toFixedPtAmt("500"), toFixedPtAmt("-500")]); }); it("should charge fee", async function () { await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), + mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")), ).to.changeTokenBalance(perp, perp, "0"); }); it("should calculate rollover amt", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, + const r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + reserveTranche.target, toFixedPtAmt("500"), ); expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -448,83 +442,24 @@ describe("PerpetualTranche", function () { }); }); - describe("when fee > 0", function () { - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("0.01")); - }); - it("should transfer the tranches in", async function () { - await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), - ).to.changeTokenBalances(rolloverInTranche, [deployer, perp], [toFixedPtAmt("-500"), toFixedPtAmt("500")]); - }); - it("should transfer the tranches out", async function () { - await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), - ).to.changeTokenBalances(reserveTranche, [deployer, perp], [toFixedPtAmt("495"), toFixedPtAmt("-495")]); - }); - it("should calculate rollover amt", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, - toFixedPtAmt("500"), - ); - expect(r.tokenOutAmt).to.eq(toFixedPtAmt("495")); - expect(r.trancheInAmt).to.eq(toFixedPtAmt("500")); - }); - }); - - describe("when fee < 0", function () { - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("-0.01")); - }); - it("should transfer the tranches in", async function () { - await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), - ).to.changeTokenBalances( - rolloverInTranche, - [deployer, perp], - [toFixedPtAmt("-495.049504950495049505"), toFixedPtAmt("495.049504950495049505")], - ); - }); - it("should transfer the tranches out", async function () { - await expect(() => - mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")), - ).to.changeTokenBalances(reserveTranche, [deployer, perp], [toFixedPtAmt("500"), toFixedPtAmt("-500")]); - }); - it("should calculate rollover amt", async function () { - const r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, - toFixedPtAmt("500"), - ); - expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); - expect(r.trancheInAmt).to.eq(toFixedPtAmt("495.049504950495049505")); - }); - }); - describe("when trancheIn is NOT yet in the reserve", async function () { let tx: Transaction, newRotationInTranche: Contract, r: any; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); // advancing to next issuance - const newRolloverInBond = await bondAt(await perp.callStatic.getDepositBond()); + const newRolloverInBond = await bondAt(await perp.getDepositBond.staticCall()); await depositIntoBond(newRolloverInBond, toFixedPtAmt("1000"), deployer); [newRotationInTranche] = await getTranches(newRolloverInBond); - await newRotationInTranche.approve(mockVault.address, toFixedPtAmt("250")); - r = await perp.callStatic.computeRolloverAmt( - newRotationInTranche.address, - collateralToken.address, - toFixedPtAmt("250"), - ); - tx = mockVault.rollover( - perp.address, - newRotationInTranche.address, - collateralToken.address, + await newRotationInTranche.approve(mockVault.target, toFixedPtAmt("250")); + r = await perp.computeRolloverAmt.staticCall( + newRotationInTranche.target, + collateralToken.target, toFixedPtAmt("250"), ); + tx = mockVault.rollover(perp.target, newRotationInTranche.target, collateralToken.target, toFixedPtAmt("250")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newRotationInTranche], [toFixedPtAmt("1250"), toFixedPtAmt("250")], @@ -533,9 +468,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(newRotationInTranche.address, toFixedPtAmt("250")) + .withArgs(newRotationInTranche.target, toFixedPtAmt("250")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("1250")); + .withArgs(collateralToken.target, toFixedPtAmt("1250")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -546,17 +481,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is a reserve tranche", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + reserveTranche.target, toFixedPtAmt("250"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("250")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("250")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("250"), toFixedPtAmt("750")], @@ -565,9 +500,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("750")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("750")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, toFixedPtAmt("250")); + .withArgs(reserveTranche.target, toFixedPtAmt("250")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -578,17 +513,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is the mature collateral", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("250"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, collateralToken.address, toFixedPtAmt("250")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, collateralToken.target, toFixedPtAmt("250")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("250"), toFixedPtAmt("500"), toFixedPtAmt("750")], @@ -597,9 +532,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("750")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("750")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("250")); + .withArgs(collateralToken.target, toFixedPtAmt("250")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -611,17 +546,17 @@ describe("PerpetualTranche", function () { let tx: Transaction, r: any; beforeEach(async function () { await rebase(collateralToken, rebaseOracle, +0.5); - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("250"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, collateralToken.address, toFixedPtAmt("250")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, collateralToken.target, toFixedPtAmt("250")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("500"), toFixedPtAmt("750")], @@ -630,9 +565,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("750")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("750")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("500")); + .withArgs(collateralToken.target, toFixedPtAmt("500")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -644,17 +579,17 @@ describe("PerpetualTranche", function () { let tx: Transaction, r: any; beforeEach(async function () { await rebase(collateralToken, rebaseOracle, -0.5); - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("250"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, collateralToken.address, toFixedPtAmt("250")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, collateralToken.target, toFixedPtAmt("250")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("750")], @@ -663,9 +598,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("750")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("750")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, "0"); + .withArgs(collateralToken.target, "0"); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("250")); @@ -676,17 +611,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is tranche and fully withdrawn", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + reserveTranche.target, toFixedPtAmt("500"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("500")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("500")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("1000")], @@ -696,9 +631,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("1000")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("1000")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, "0"); + .withArgs(reserveTranche.target, "0"); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -709,17 +644,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is collateral and fully withdrawn", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("500"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, collateralToken.address, toFixedPtAmt("500")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, collateralToken.target, toFixedPtAmt("500")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], ["0", toFixedPtAmt("500"), toFixedPtAmt("1000")], @@ -728,9 +663,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("1000")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("1000")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, "0"); + .withArgs(collateralToken.target, "0"); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -741,17 +676,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is partially redeemed", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + reserveTranche.target, toFixedPtAmt("100"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("100")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("100")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("400"), toFixedPtAmt("600")], @@ -761,9 +696,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("600")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("600")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, toFixedPtAmt("400")); + .withArgs(reserveTranche.target, toFixedPtAmt("400")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("100")); @@ -774,17 +709,17 @@ describe("PerpetualTranche", function () { describe("when tokenOut is NOT covered", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + reserveTranche.target, toFixedPtAmt("2000"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("2000")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, reserveTranche.target, toFixedPtAmt("2000")); await tx; }); it("should update the reserve (only transfers covered amount)", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, rolloverInTranche], [toFixedPtAmt("500"), toFixedPtAmt("1000")], @@ -794,9 +729,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("1000")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("1000")) .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, "0"); + .withArgs(reserveTranche.target, "0"); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); @@ -804,88 +739,20 @@ describe("PerpetualTranche", function () { }); }); - describe("when tokenOut is NOT covered and fee > 0", async function () { - let tx: Transaction, r: any; - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("0.01")); - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, - toFixedPtAmt("2000"), - ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("2000")); - await tx; - }); - - it("should update the reserve (only transfers covered amount)", async function () { - await checkReserveComposition( - perp, - [collateralToken, rolloverInTranche], - [toFixedPtAmt("500"), toFixedPtAmt("1005.050505050505050506")], - ); - }); - - it("should emit reserve synced", async function () { - await expect(tx) - .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("1005.050505050505050506")) - .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, "0"); - }); - it("should compute the rollover amounts", async function () { - expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); - expect(r.trancheInAmt).to.eq(toFixedPtAmt("505.050505050505050506")); - }); - }); - - describe("when tokenOut is NOT covered and fee < 0", async function () { - let tx: Transaction, r: any; - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("-0.01")); - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - reserveTranche.address, - toFixedPtAmt("2000"), - ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, reserveTranche.address, toFixedPtAmt("2000")); - await tx; - }); - - it("should update the reserve (only transfers covered amount)", async function () { - await checkReserveComposition( - perp, - [collateralToken, rolloverInTranche], - [toFixedPtAmt("500"), toFixedPtAmt("995.049504950495049505")], - ); - }); - - it("should emit reserve synced", async function () { - await expect(tx) - .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("995.049504950495049505")) - .to.emit(perp, "ReserveSynced") - .withArgs(reserveTranche.address, "0"); - }); - it("should compute the rollover amounts", async function () { - expect(r.tokenOutAmt).to.eq(toFixedPtAmt("500")); - expect(r.trancheInAmt).to.eq(toFixedPtAmt("495.049504950495049505")); - }); - }); - describe("when valid rollover", async function () { let tx: Transaction, r: any; beforeEach(async function () { - r = await perp.callStatic.computeRolloverAmt( - rolloverInTranche.address, - collateralToken.address, + r = await perp.computeRolloverAmt.staticCall( + rolloverInTranche.target, + collateralToken.target, toFixedPtAmt("100"), ); - tx = mockVault.rollover(perp.address, rolloverInTranche.address, collateralToken.address, toFixedPtAmt("100")); + tx = mockVault.rollover(perp.target, rolloverInTranche.target, collateralToken.target, toFixedPtAmt("100")); await tx; }); it("should update the reserve", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranche, rolloverInTranche], [toFixedPtAmt("400"), toFixedPtAmt("500"), toFixedPtAmt("600")], @@ -895,9 +762,9 @@ describe("PerpetualTranche", function () { it("should emit reserve synced", async function () { await expect(tx) .to.emit(perp, "ReserveSynced") - .withArgs(rolloverInTranche.address, toFixedPtAmt("600")) + .withArgs(rolloverInTranche.target, toFixedPtAmt("600")) .to.emit(perp, "ReserveSynced") - .withArgs(collateralToken.address, toFixedPtAmt("400")); + .withArgs(collateralToken.target, toFixedPtAmt("400")); }); it("should compute the rollover amounts", async function () { expect(r.tokenOutAmt).to.eq(toFixedPtAmt("100")); diff --git a/spot-contracts/test/rollover-vault/RolloverVault.ts b/spot-contracts/test/rollover-vault/RolloverVault.ts index 7a23860b..64d8441a 100644 --- a/spot-contracts/test/rollover-vault/RolloverVault.ts +++ b/spot-contracts/test/rollover-vault/RolloverVault.ts @@ -1,6 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; -import { Contract, Transaction, Signer, constants } from "ethers"; +import { Contract, Transaction, Signer } from "ethers"; import { setupCollateralToken, mintCollteralToken, @@ -11,14 +11,13 @@ import { getTranches, getDepositBond, advancePerpQueueToBondMaturity, + DMock, } from "../helpers"; -import { smock, FakeContract } from "@defi-wonderland/smock"; - -use(smock.matchers); let vault: Contract, - perp: FakeContract, - feePolicy: FakeContract, + trancheManager: Contract, + perp: Contract, + feePolicy: Contract, collateralToken: Contract, deployer: Signer, otherUser: Signer; @@ -33,19 +32,30 @@ describe("RolloverVault", function () { ({ collateralToken } = await setupCollateralToken("Bitcoin", "BTC")); await mintCollteralToken(collateralToken, toFixedPtAmt("1000"), deployer); - const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); - perp = await smock.fake(PerpetualTranche); - await perp.underlying.returns(collateralToken.address); - - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); - - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await collateralToken.approve(vault.address, toFixedPtAmt("1")); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.vault.returns(vault.address); + perp = new DMock(await ethers.getContractFactory("PerpetualTranche")); + await perp.deploy(); + await perp.mockMethod("underlying()", [collateralToken.target]); + + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); + + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.mockMethod("vault()", [vault.target]); }); afterEach(async function () { @@ -64,24 +74,25 @@ describe("RolloverVault", function () { }); it("should set ext service references", async function () { - expect(await vault.perp()).to.eq(perp.address); + expect(await vault.perp()).to.eq(perp.target); }); it("should set deposit asset reference", async function () { - expect(await vault.underlying()).to.eq(collateralToken.address); + expect(await vault.underlying()).to.eq(collateralToken.target); }); it("should set initial param values", async function () { expect(await vault.minDeploymentAmt()).to.eq("0"); expect(await vault.reservedUnderlyingBal()).to.eq("0"); expect(await vault.reservedSubscriptionPerc()).to.eq("0"); + expect(await vault.lastRebalanceTimestampSec()).not.to.eq("0"); }); it("should initialize lists", async function () { expect(await vault.assetCount()).to.eq(1); - expect(await vault.assetAt(0)).to.eq(collateralToken.address); - expect(await vault.isVaultAsset(collateralToken.address)).to.eq(true); - expect(await vault.isVaultAsset(perp.address)).to.eq(false); + expect(await vault.assetAt(0)).to.eq(collateralToken.target); + expect(await vault.isVaultAsset(collateralToken.target)).to.eq(true); + expect(await vault.isVaultAsset(perp.target)).to.eq(false); }); it("should NOT be paused", async function () { @@ -167,6 +178,47 @@ describe("RolloverVault", function () { }); }); + describe("#pauseRebalance", function () { + beforeEach(async function () { + await vault.updateKeeper(await otherUser.getAddress()); + }); + + describe("when triggered by non-owner", function () { + it("should revert", async function () { + await expect(vault.connect(deployer).pauseRebalance()).to.be.revertedWithCustomError(vault, "UnauthorizedCall"); + }); + }); + + describe("when valid", function () { + it("should stop rebalance", async function () { + await vault.connect(otherUser).pauseRebalance(); + expect(await vault.lastRebalanceTimestampSec()).to.eq(18446744073709551615n); + }); + }); + }); + + describe("#unpauseRebalance", function () { + beforeEach(async function () { + await vault.updateKeeper(await otherUser.getAddress()); + }); + + describe("when triggered by non-owner", function () { + it("should revert", async function () { + await expect(vault.connect(deployer).unpauseRebalance()).to.be.revertedWithCustomError( + vault, + "UnauthorizedCall", + ); + }); + }); + + describe("when valid", function () { + it("should restart rebalance", async function () { + await vault.connect(otherUser).unpauseRebalance(); + expect(await vault.lastRebalanceTimestampSec()).to.lt(ethers.MaxUint256); + }); + }); + }); + describe("#transferERC20", function () { let transferToken: Contract, toAddress: string; @@ -174,21 +226,21 @@ describe("RolloverVault", function () { const Token = await ethers.getContractFactory("MockERC20"); transferToken = await Token.deploy(); await transferToken.init("Mock Token", "MOCK"); - await transferToken.mint(vault.address, "100"); + await transferToken.mint(vault.target, "100"); toAddress = await deployer.getAddress(); }); describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect( - vault.connect(otherUser).transferERC20(transferToken.address, toAddress, "100"), - ).to.be.revertedWith("Ownable: caller is not the owner"); + await expect(vault.connect(otherUser).transferERC20(transferToken.target, toAddress, "100")).to.be.revertedWith( + "Ownable: caller is not the owner", + ); }); }); describe("when non vault asset", function () { it("should transfer", async function () { - await expect(() => vault.transferERC20(transferToken.address, toAddress, "100")).to.changeTokenBalance( + await expect(() => vault.transferERC20(transferToken.target, toAddress, "100")).to.changeTokenBalance( transferToken, deployer, "100", @@ -206,8 +258,8 @@ describe("RolloverVault", function () { describe("when perp", function () { it("should not revert", async function () { - await perp.transfer.returns(() => true); - await expect(vault.transferERC20(perp.address, toAddress, toFixedPtAmt("100"))).not.to.be.reverted; + await perp.mockMethod("transfer(address,uint256)", [true]); + await expect(vault.transferERC20(perp.target, toAddress, toFixedPtAmt("100"))).not.to.be.reverted; }); }); @@ -219,7 +271,7 @@ describe("RolloverVault", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); const issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 4800, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, @@ -228,7 +280,7 @@ describe("RolloverVault", function () { const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -237,20 +289,26 @@ describe("RolloverVault", function () { await perp.updateTolerableTrancheMaturity(1200, 4800); await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.updateVault(vault.address); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); const bond = await getDepositBond(perp); const tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await advancePerpQueueToBondMaturity(perp, bond); - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); await vault.deploy(); expect(await vault.assetCount()).to.eq(2); }); @@ -270,7 +328,7 @@ describe("RolloverVault", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(vault.connect(deployer).updateFeePolicy(constants.AddressZero)).to.be.revertedWith( + await expect(vault.connect(deployer).updateFeePolicy(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); @@ -279,71 +337,19 @@ describe("RolloverVault", function () { describe("when triggered by owner", function () { let newFeePolicy: Contract; beforeEach(async function () { - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - newFeePolicy = await smock.fake(FeePolicy); - await newFeePolicy.decimals.returns(8); - tx = await vault.connect(otherUser).updateFeePolicy(newFeePolicy.address); + newFeePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await newFeePolicy.deploy(); + await newFeePolicy.mockMethod("decimals()", [8]); + tx = await vault.connect(otherUser).updateFeePolicy(newFeePolicy.target); await tx; }); it("should update the fee policy", async function () { - expect(await vault.feePolicy()).to.eq(newFeePolicy.address); - }); - }); - }); - - describe("#updateReservedUnderlyingBal", function () { - let tx: Transaction; - beforeEach(async function () { - await vault.connect(deployer).updateKeeper(await otherUser.getAddress()); - }); - - describe("when triggered by non-keeper", function () { - it("should revert", async function () { - await expect(vault.connect(deployer).updateReservedUnderlyingBal(0)).to.be.revertedWithCustomError( - vault, - "UnauthorizedCall", - ); - }); - }); - - describe("when triggered by keeper", function () { - beforeEach(async function () { - tx = await vault.connect(otherUser).updateReservedUnderlyingBal(toFixedPtAmt("1000")); - await tx; - }); - it("should update the min deployment amount", async function () { - expect(await vault.reservedUnderlyingBal()).to.eq(toFixedPtAmt("1000")); - }); - }); - }); - - describe("#updateReservedUnderlyingBal", function () { - let tx: Transaction; - beforeEach(async function () { - await vault.connect(deployer).updateKeeper(await otherUser.getAddress()); - }); - - describe("when triggered by non-keeper", function () { - it("should revert", async function () { - await expect(vault.connect(deployer).updateReservedUnderlyingBal(0)).to.be.revertedWithCustomError( - vault, - "UnauthorizedCall", - ); - }); - }); - - describe("when triggered by keeper", function () { - beforeEach(async function () { - tx = await vault.connect(otherUser).updateReservedUnderlyingBal(toFixedPtAmt("1000")); - await tx; - }); - it("should update the min underlying balance", async function () { - expect(await vault.reservedUnderlyingBal()).to.eq(toFixedPtAmt("1000")); + expect(await vault.feePolicy()).to.eq(newFeePolicy.target); }); }); }); - describe("#updateReservedSubscriptionPerc", function () { + describe("#updateLiquidityLimits", function () { let tx: Transaction; beforeEach(async function () { await vault.connect(deployer).updateKeeper(await otherUser.getAddress()); @@ -351,20 +357,25 @@ describe("RolloverVault", function () { describe("when triggered by non-keeper", function () { it("should revert", async function () { - await expect(vault.connect(deployer).updateReservedSubscriptionPerc(0)).to.be.revertedWithCustomError( - vault, - "UnauthorizedCall", - ); + await expect( + vault + .connect(deployer) + .updateLiquidityLimits(toFixedPtAmt("1000"), toFixedPtAmt("100000"), toPercFixedPtAmt("0.25")), + ).to.be.revertedWithCustomError(vault, "UnauthorizedCall"); }); }); describe("when triggered by keeper", function () { beforeEach(async function () { - tx = await vault.connect(otherUser).updateReservedSubscriptionPerc(toPercFixedPtAmt("0.1")); + tx = await vault + .connect(otherUser) + .updateLiquidityLimits(toFixedPtAmt("1000"), toFixedPtAmt("100000"), toPercFixedPtAmt("0.25")); await tx; }); - it("should update the min underlying balance", async function () { - expect(await vault.reservedSubscriptionPerc()).to.eq(toPercFixedPtAmt("0.1")); + it("should update the liquidity parameters", async function () { + expect(await vault.minDeploymentAmt()).to.eq(toFixedPtAmt("1000")); + expect(await vault.reservedUnderlyingBal()).to.eq(toFixedPtAmt("100000")); + expect(await vault.reservedSubscriptionPerc()).to.eq(toPercFixedPtAmt("0.25")); }); }); }); @@ -377,7 +388,7 @@ describe("RolloverVault", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { - await expect(vault.connect(deployer).updateKeeper(constants.AddressZero)).to.be.revertedWith( + await expect(vault.connect(deployer).updateKeeper(ethers.ZeroAddress)).to.be.revertedWith( "Ownable: caller is not the owner", ); }); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_deploy.ts b/spot-contracts/test/rollover-vault/RolloverVault_deploy.ts index 3f85a0eb..07ae3d54 100644 --- a/spot-contracts/test/rollover-vault/RolloverVault_deploy.ts +++ b/spot-contracts/test/rollover-vault/RolloverVault_deploy.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Signer, Transaction } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, @@ -16,11 +15,11 @@ import { advancePerpQueue, advancePerpQueueToBondMaturity, advancePerpQueueToRollover, - checkReserveComposition, - checkVaultAssetComposition, + checkPerpComposition, + checkVaultComposition, rebase, + DMock, } from "../helpers"; -use(smock.matchers); let vault: Contract; let perp: Contract; @@ -47,21 +46,22 @@ describe("RolloverVault", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 4800, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); - await feePolicy.computePerpRolloverFeePerc.returns("0"); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -70,10 +70,19 @@ describe("RolloverVault", function () { await perp.updateTolerableTrancheMaturity(1200, 4800); await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); reserveTranches = []; for (let i = 0; i < 4; i++) { @@ -81,25 +90,25 @@ describe("RolloverVault", function () { const tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); reserveTranches.push(tranches[0]); await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3)], [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - rolloverInBond = await bondAt(await perp.callStatic.getDepositBond()); + rolloverInBond = await bondAt(await perp.getDepositBond.staticCall()); rolloverInTranches = await getTranches(rolloverInBond); await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); - await collateralToken.approve(vault.address, toFixedPtAmt("1")); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); - await checkVaultAssetComposition(vault, [collateralToken], ["0"]); + await checkVaultComposition(vault, [collateralToken], ["0"]); expect(await vault.assetCount()).to.eq(1); }); @@ -116,13 +125,13 @@ describe("RolloverVault", function () { describe("when reservedUnderlyingBal is not set", function () { beforeEach(async function () { - await vault.updateReservedUnderlyingBal(toFixedPtAmt("0")); + await vault.updateLiquidityLimits(toFixedPtAmt("0"), toFixedPtAmt("0"), toPercFixedPtAmt("0")); }); describe("when usable balance is lower than the min deployment", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("999")); - await vault.updateMinDeploymentAmt(toFixedPtAmt("1000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("999")); + await vault.updateLiquidityLimits(toFixedPtAmt("1000"), toFixedPtAmt("0"), toPercFixedPtAmt("0")); }); it("should revert", async function () { await expect(vault.deploy()).to.be.revertedWithCustomError(vault, "InsufficientDeployment"); @@ -131,8 +140,8 @@ describe("RolloverVault", function () { describe("when usable balance is higher than the min deployment", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); - await vault.updateMinDeploymentAmt(toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); + await vault.updateLiquidityLimits(toFixedPtAmt("100"), toFixedPtAmt("0"), toPercFixedPtAmt("0")); }); it("should not revert", async function () { await expect(vault.deploy()).not.to.be.reverted; @@ -142,13 +151,12 @@ describe("RolloverVault", function () { describe("when reservedUnderlyingBal is set", function () { beforeEach(async function () { - await vault.updateReservedUnderlyingBal(toFixedPtAmt("25")); + await vault.updateLiquidityLimits(toFixedPtAmt("0"), toFixedPtAmt("25"), toPercFixedPtAmt("0")); }); describe("when usable balance is lower than the reservedUnderlyingBal", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("20")); - await vault.updateMinDeploymentAmt(toFixedPtAmt("1")); + await collateralToken.transfer(vault.target, toFixedPtAmt("20")); }); it("should revert", async function () { await expect(vault.deploy()).to.be.revertedWithCustomError(vault, "InsufficientDeployment"); @@ -157,8 +165,8 @@ describe("RolloverVault", function () { describe("when usable balance is lower than the min deployment", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("125")); - await vault.updateMinDeploymentAmt(toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("125")); + await vault.updateLiquidityLimits(toFixedPtAmt("100"), toFixedPtAmt("25"), toPercFixedPtAmt("0")); }); it("should revert", async function () { await expect(vault.deploy()).to.be.revertedWithCustomError(vault, "InsufficientDeployment"); @@ -167,8 +175,8 @@ describe("RolloverVault", function () { describe("when usable balance is higher than the min deployment", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("126")); - await vault.updateMinDeploymentAmt(toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("126")); + await vault.updateLiquidityLimits(toFixedPtAmt("100"), toFixedPtAmt("25"), toPercFixedPtAmt("0")); }); it("should not revert", async function () { await expect(vault.deploy()).not.to.be.reverted; @@ -180,23 +188,23 @@ describe("RolloverVault", function () { let newTranchesIn; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - const newBondIn = await bondAt(await perp.callStatic.getDepositBond()); + const newBondIn = await bondAt(await perp.getDepositBond.staticCall()); newTranchesIn = await getTranches(newBondIn); - await checkReserveComposition(perp, [collateralToken], [toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken], [toFixedPtAmt("800")]); }); describe("when balance covers just 1 token", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, newTranchesIn[0]], [toFixedPtAmt("798"), toFixedPtAmt("2")], @@ -206,16 +214,16 @@ describe("RolloverVault", function () { describe("when balance covers just 1 token exactly", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("10000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10000")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("6800"), toFixedPtAmt("3200")], ); - await checkReserveComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); }); }); }); @@ -223,48 +231,49 @@ describe("RolloverVault", function () { describe("when one trancheIn one tokenOut (near mature tranche)", function () { let curTranchesIn, newTranchesIn; beforeEach(async function () { - await advancePerpQueueToBondMaturity(perp, await bondAt(reserveTranches[2].bond())); - const curBondIn = await bondAt(await perp.callStatic.getDepositBond()); + await advancePerpQueueToBondMaturity(perp, await bondAt(await reserveTranches[2].bond())); + const curBondIn = await bondAt(await perp.getDepositBond.staticCall()); + await depositIntoBond(curBondIn, toFixedPtAmt("10"), deployer); curTranchesIn = await getTranches(curBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10000")); await vault.deploy(); await advancePerpQueueToRollover(perp, curBondIn); - const newBondIn = await bondAt(await perp.callStatic.getDepositBond()); + const newBondIn = await bondAt(await perp.getDepositBond.staticCall()); newTranchesIn = await getTranches(newBondIn); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[3], curTranchesIn[1]], [toFixedPtAmt("6600"), toFixedPtAmt("200"), toFixedPtAmt("3200")], ); - await checkReserveComposition(perp, [collateralToken, curTranchesIn[0]], ["0", toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken, curTranchesIn[0]], ["0", toFixedPtAmt("800")]); }); describe("when balance covers just 1 token", function () { it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1], reserveTranches[3]], [toFixedPtAmt("6600"), toFixedPtAmt("3200"), toFixedPtAmt("200")], ); - await checkReserveComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); }); }); describe("when balance covers just 1 token exactly", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("8500")); + await collateralToken.transfer(vault.target, toFixedPtAmt("8500")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[3], newTranchesIn[1]], [toFixedPtAmt("15100"), toFixedPtAmt("200"), toFixedPtAmt("3200")], ); - await checkReserveComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken, newTranchesIn[0]], ["0", toFixedPtAmt("800")]); }); }); }); @@ -272,16 +281,16 @@ describe("RolloverVault", function () { describe("when one trancheIn many tokenOut", function () { describe("when balance covers just 1 token", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, rolloverInTranches[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), rolloverInTranches[0]], [toFixedPtAmt("198"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("2")], @@ -291,16 +300,16 @@ describe("RolloverVault", function () { describe("when balance covers just 1 token exactly", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, rolloverInTranches[1]], [toFixedPtAmt("200"), toFixedPtAmt("800")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), rolloverInTranches[0]], ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], @@ -310,16 +319,16 @@ describe("RolloverVault", function () { describe("when balance covers many tokens", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("4000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("4000")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[1], rolloverInTranches[1]], [toFixedPtAmt("2200"), toFixedPtAmt("200"), toFixedPtAmt("1600")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-2), rolloverInTranches[0]], ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("400")], @@ -332,16 +341,16 @@ describe("RolloverVault", function () { describe("when balance covers many tokens", async function () { beforeEach(async function () { await rebase(collateralToken, rebaseOracle, -0.9); - await collateralToken.transfer(vault.address, toFixedPtAmt("600")); + await collateralToken.transfer(vault.target, toFixedPtAmt("600")); }); it("should rollover", async function () { await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[1], rolloverInTranches[1]], [toFixedPtAmt("20"), toFixedPtAmt("200"), toFixedPtAmt("480")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-2), rolloverInTranches[0]], ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("120")], @@ -350,55 +359,11 @@ describe("RolloverVault", function () { }); }); - describe("when rollover fee is +ve", function () { - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("0.01")); - await collateralToken.transfer(vault.address, toFixedPtAmt("1500")); - }); - - it("should rollover", async function () { - await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( - vault, - [collateralToken, reserveTranches[1], rolloverInTranches[1]], - [toFixedPtAmt("200"), toFixedPtAmt("96.999999999999999999"), toFixedPtAmt("1200")], - ); - await checkReserveComposition( - perp, - [collateralToken, reserveTranches[1], reserveTranches[2], reserveTranches[3], rolloverInTranches[0]], - ["0", toFixedPtAmt("103.000000000000000001"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("300")], - ); - }); - }); - - describe("when rollover fee is -ve", function () { - beforeEach(async function () { - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("-0.01")); - await collateralToken.transfer(vault.address, toFixedPtAmt("1500")); - }); - - it("should rollover", async function () { - await expect(vault.deploy()).not.to.be.reverted; - await checkVaultAssetComposition( - vault, - [collateralToken, reserveTranches[1], rolloverInTranches[1]], - [toFixedPtAmt("200"), toFixedPtAmt("102.999999999999999999"), toFixedPtAmt("1200")], - ); - await checkReserveComposition( - perp, - [collateralToken, reserveTranches[1], reserveTranches[2], reserveTranches[3], rolloverInTranches[0]], - ["0", toFixedPtAmt("97.000000000000000001"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("300")], - ); - }); - }); - describe("typical deploy", function () { let txFn: Promise; beforeEach(async function () { await rebase(collateralToken, rebaseOracle, -0.9); - await feePolicy.computePerpRolloverFeePerc.returns(toPercFixedPtAmt("-0.01")); - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); - + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); txFn = () => vault.deploy(); }); @@ -406,44 +371,33 @@ describe("RolloverVault", function () { const tx = txFn(); // Tranche - await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[0].address, toFixedPtAmt("200")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[1].address, toFixedPtAmt("800")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[0].target, toFixedPtAmt("200")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[1].target, toFixedPtAmt("800")); // Rollover - await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[1].address, toFixedPtAmt("200")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[1].target, toFixedPtAmt("200")); // Recover - await expect(tx) - .to.emit(vault, "AssetSynced") - .withArgs(rolloverInTranches[0].address, toFixedPtAmt("0.000000000000000118")); - await expect(tx) - .to.emit(vault, "AssetSynced") - .withArgs(rolloverInTranches[1].address, toFixedPtAmt("475.247524752475248")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[0].target, toFixedPtAmt("0")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(rolloverInTranches[1].target, toFixedPtAmt("480")); // Final - await expect(tx) - .to.emit(vault, "AssetSynced") - .withArgs(collateralToken.address, toFixedPtAmt("425.940594059405940000")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("420")); }); it("should update the list of deployed assets", async function () { await txFn(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, - [collateralToken, reserveTranches[1], rolloverInTranches[0], rolloverInTranches[1]], - [ - toFixedPtAmt("425.940594059405940000"), - toFixedPtAmt("200"), - toFixedPtAmt("0.000000000000000118"), - toFixedPtAmt("475.247524752475248"), - ], + [collateralToken, reserveTranches[1], rolloverInTranches[1]], + [toFixedPtAmt("420"), toFixedPtAmt("200"), toFixedPtAmt("480")], ); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, reserveTranches[2], reserveTranches[3], rolloverInTranches[0]], - ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("118.811881188118811882")], + ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("120")], ); }); }); @@ -451,9 +405,9 @@ describe("RolloverVault", function () { describe("deploy limit", function () { async function setupDeployment() { - const curBondIn = await bondAt(await perp.callStatic.getDepositBond()); + const curBondIn = await bondAt(await perp.getDepositBond.staticCall()); await advancePerpQueueToRollover(perp, curBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); } beforeEach(async function () { @@ -469,7 +423,7 @@ describe("RolloverVault", function () { await expect(vault.deploy()).to.be.revertedWithCustomError(vault, "DeployedCountOverLimit"); }); it("redemption should be within gas limit", async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("10")); + await collateralToken.approve(vault.target, toFixedPtAmt("10")); await vault.deposit(toFixedPtAmt("10")); await expect(vault.redeem(await vault.balanceOf(await deployer.getAddress()))).not.to.be.reverted; }); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_deposit_redeem.ts b/spot-contracts/test/rollover-vault/RolloverVault_deposit_redeem.ts index 80ec756e..188b2ce5 100644 --- a/spot-contracts/test/rollover-vault/RolloverVault_deposit_redeem.ts +++ b/spot-contracts/test/rollover-vault/RolloverVault_deposit_redeem.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Signer, BigNumber } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, @@ -14,13 +13,12 @@ import { getDepositBond, advancePerpQueue, advancePerpQueueToBondMaturity, - checkReserveComposition, - checkVaultAssetComposition, + checkPerpComposition, + checkVaultComposition, rebase, toPercFixedPtAmt, - advancePerpQueueUpToBondMaturity, + DMock, } from "../helpers"; -use(smock.matchers); let deployer: Signer; let deployerAddress: string; @@ -54,21 +52,22 @@ describe("RolloverVault", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 4800, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); - await feePolicy.computePerpRolloverFeePerc.returns("0"); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -77,10 +76,19 @@ describe("RolloverVault", function () { await perp.updateTolerableTrancheMaturity(1200, 4800); await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); reserveTranches = []; for (let i = 0; i < 3; i++) { @@ -88,24 +96,24 @@ describe("RolloverVault", function () { const tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); reserveTranches.push(tranches[0]); await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches], ["0", toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - rolloverInBond = await bondAt(await perp.callStatic.getDepositBond()); + rolloverInBond = await bondAt(await perp.getDepositBond.staticCall()); rolloverInTranches = await getTranches(rolloverInBond); await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); - await collateralToken.approve(vault.address, toFixedPtAmt("1")); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); expect(await vault.assetCount()).to.eq(1); expect(await vault.vaultAssetBalance(await vault.underlying())).to.eq(0); @@ -114,125 +122,125 @@ describe("RolloverVault", function () { describe("#getTVL", function () { describe("when vault is empty", function () { it("should return 0 vaule", async function () { - expect(await vault.callStatic.getTVL()).to.eq(0); - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(0); - expect(await vault.callStatic.getVaultAssetValue(perp.address)).to.eq(0); + expect(await vault.getTVL.staticCall()).to.eq(0); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(0); + expect(await vault.getVaultAssetValue.staticCall(perp.target)).to.eq(0); }); }); describe("when vault has only usable balance", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("100")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(toFixedPtAmt("100")); - expect(await vault.callStatic.getVaultAssetValue(perp.address)).to.eq(0); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("100")); + expect(await vault.getVaultAssetValue.staticCall(perp.target)).to.eq(0); }); }); describe("when vault has only deployed balance", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); await vault.deploy(); expect(await vault.vaultAssetBalance(await vault.underlying())).to.eq(0); expect(await vault.assetCount()).to.eq(3); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("100")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(0); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("20")); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq(toFixedPtAmt("80")); - expect(await vault.callStatic.getVaultAssetValue(perp.address)).to.eq(0); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(0); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("20")); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq(toFixedPtAmt("80")); + expect(await vault.getVaultAssetValue.staticCall(perp.target)).to.eq(0); }); }); describe("when vault has many balances", function () { beforeEach(async function () { - await perp.transfer(vault.address, toFixedPtAmt("100")); - await collateralToken.transfer(vault.address, toFixedPtAmt("2000")); + await perp.transfer(vault.target, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("2000")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2100")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(perp.address)).to.eq("0"); - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(toFixedPtAmt("1100")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("200")); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq(toFixedPtAmt("800")); + expect(await vault.getVaultAssetValue.staticCall(perp.target)).to.eq("0"); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("1100")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("200")); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq(toFixedPtAmt("800")); }); }); describe("when vault has many balances and rebases up", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("2000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("2000")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); await rebase(collateralToken, rebaseOracle, 0.1); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2310")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2310")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(toFixedPtAmt("1210")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("200")); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq(toFixedPtAmt("900")); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("1210")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("200")); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq(toFixedPtAmt("900")); }); }); describe("when vault has many balances and rebases down", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("2000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("2000")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); await rebase(collateralToken, rebaseOracle, -0.1); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("1890")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1890")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(toFixedPtAmt("990")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("200")); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq(toFixedPtAmt("700")); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("990")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("200")); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq(toFixedPtAmt("700")); }); }); describe("when vault has many balances and rebases down below threshold", function () { beforeEach(async function () { - await collateralToken.transfer(vault.address, toFixedPtAmt("5000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("5000")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); await rebase(collateralToken, rebaseOracle, -0.9); }); it("should return tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("510")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("510")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq(toFixedPtAmt("410")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("100")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[1].address)).to.eq("0"); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[2].address)).to.eq("0"); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[0].address)).to.eq(toFixedPtAmt("0")); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq("0"); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq(toFixedPtAmt("410")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("100")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[1].target)).to.eq("0"); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[2].target)).to.eq("0"); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[0].target)).to.eq(toFixedPtAmt("0")); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq("0"); }); }); describe("when vault has some dust balances", function () { beforeEach(async function () { - await perp.transfer(vault.address, toFixedPtAmt("100")); - await collateralToken.transfer(vault.address, toFixedPtAmt("2000")); + await perp.transfer(vault.target, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("2000")); await vault.deploy(); - await vault["recover(address)"](perp.address); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); - await checkVaultAssetComposition( + await vault["recover(address)"](perp.target); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); + await checkVaultComposition( vault, [ collateralToken, @@ -254,27 +262,27 @@ describe("RolloverVault", function () { }); it("should return tvl excluding the dust", async function () { // balances sum up to 2200 but tvl will exclude 0.000000000000000133 - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2199.999999999999999866")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2199.999999999999999866")); }); it("should return asset value", async function () { - expect(await vault.callStatic.getVaultAssetValue(perp.address)).to.eq("0"); - expect(await vault.callStatic.getVaultAssetValue(collateralToken.address)).to.eq( + expect(await vault.getVaultAssetValue.staticCall(perp.target)).to.eq("0"); + expect(await vault.getVaultAssetValue.staticCall(collateralToken.target)).to.eq( toFixedPtAmt("1266.666666666666666"), ); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[0].address)).to.eq(toFixedPtAmt("200")); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[1].address)).to.eq( + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[0].target)).to.eq(toFixedPtAmt("200")); + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[1].target)).to.eq( toFixedPtAmt("33.333333333333333333"), ); - expect(await vault.callStatic.getVaultAssetValue(reserveTranches[2].address)).to.eq( + expect(await vault.getVaultAssetValue.staticCall(reserveTranches[2].target)).to.eq( toFixedPtAmt("33.333333333333333333"), ); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[1].address)).to.eq( + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[1].target)).to.eq( toFixedPtAmt("666.6666666666666672"), ); }); it("should return no asset value for dust", async function () { - expect(await rolloverInTranches[0].balanceOf(vault.address)).eq("133"); - expect(await vault.callStatic.getVaultAssetValue(rolloverInTranches[0].address)).to.eq("0"); + expect(await rolloverInTranches[0].balanceOf(vault.target)).eq("133"); + expect(await vault.getVaultAssetValue.staticCall(rolloverInTranches[0].target)).to.eq("0"); }); }); }); @@ -284,14 +292,14 @@ describe("RolloverVault", function () { describe("when deposit amount is zero", async function () { it("should return zero", async function () { - expect(await vault.callStatic.deposit("0")).to.eq("0"); + expect(await vault.deposit.staticCall("0")).to.eq("0"); }); }); describe("when total supply = 0", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { await expect(() => vault.deposit(toFixedPtAmt("100"))).to.changeTokenBalances( @@ -301,25 +309,25 @@ describe("RolloverVault", function () { ); }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], ["0"]); + await checkVaultComposition(vault, [collateralToken], ["0"]); await vault.deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("100")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("100")]); }); it("should mint notes", async function () { await expect(() => vault.deposit(toFixedPtAmt("100"))).to.changeTokenBalances(vault, [deployer], [noteAmt]); }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("100").mul("1000000")); + expect(noteAmt).to.eq(toFixedPtAmt("100") * 1000000n); }); }); describe("when total supply > 0 and tvl = ts", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.connect(otherUser).callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.connect(otherUser).deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { await expect(() => vault.connect(otherUser).deposit(toFixedPtAmt("100"))).to.changeTokenBalances( @@ -330,9 +338,9 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("100")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("100")]); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("200")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("200")]); }); it("should mint notes", async function () { @@ -343,18 +351,18 @@ describe("RolloverVault", function () { ); }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("100").mul("1000000")); + expect(noteAmt).to.eq(toFixedPtAmt("100") * 1000000n); }); }); describe("when total supply > 0 and tvl > ts", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); - await collateralToken.transfer(vault.address, toFixedPtAmt("100")); + await collateralToken.transfer(vault.target, toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.connect(otherUser).callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.connect(otherUser).deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { @@ -366,9 +374,9 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("200")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("200")]); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("300")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("300")]); }); it("should mint notes", async function () { @@ -379,18 +387,18 @@ describe("RolloverVault", function () { ); }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("100").mul("500000")); + expect(noteAmt).to.eq(toFixedPtAmt("100") * 500000n); }); }); describe("when total supply > 0 and tvl < ts", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await rebase(collateralToken, rebaseOracle, -0.5); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.connect(otherUser).callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.connect(otherUser).deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { @@ -402,9 +410,9 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("50")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("50")]); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("150")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("150")]); }); it("should mint notes", async function () { @@ -416,17 +424,17 @@ describe("RolloverVault", function () { }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("100").mul("2000000")); + expect(noteAmt).to.eq(toFixedPtAmt("100") * 2000000n); }); }); describe("when total supply > 0 and vault has deployed assets", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.connect(otherUser).callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.connect(otherUser).deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { await expect(() => vault.connect(otherUser).deposit(toFixedPtAmt("100"))).to.changeTokenBalances( @@ -437,9 +445,9 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("100")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("100")]); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("200")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("200")]); }); it("should mint notes", async function () { @@ -450,19 +458,30 @@ describe("RolloverVault", function () { ); }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("100").mul("1000000")); + expect(noteAmt).to.eq(toFixedPtAmt("100") * 1000000n); }); }); describe("fee > 0", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); - await feePolicy.computeVaultMintFeePerc.returns(toPercFixedPtAmt("0.05")); + await feePolicy.clearMockMethod("computeDeviationRatio((uint256,uint256,uint256))"); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("600"), toFixedPtAmt("100"), "200"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("600"), toFixedPtAmt("200"), "200"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.05")]); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - noteAmt = await vault.connect(otherUser).callStatic.deposit(toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); + noteAmt = await vault.connect(otherUser).deposit.staticCall(toFixedPtAmt("100")); }); it("should transfer underlying", async function () { await expect(() => vault.connect(otherUser).deposit(toFixedPtAmt("100"))).to.changeTokenBalances( @@ -472,9 +491,9 @@ describe("RolloverVault", function () { ); }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("100")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("100")]); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("200")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("200")]); }); it("should mint notes", async function () { @@ -485,7 +504,7 @@ describe("RolloverVault", function () { ); }); it("should return the note amount", async function () { - expect(noteAmt).to.eq(toFixedPtAmt("95").mul("1000000")); + expect(noteAmt).to.eq(toFixedPtAmt("95") * 1000000n); }); }); }); @@ -501,34 +520,34 @@ describe("RolloverVault", function () { describe("when redeem amount is zero", async function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); }); it("should return []", async function () { - expect(await vault.callStatic.redeem("0")).to.deep.eq([]); + expect(await vault.redeem.staticCall("0")).to.deep.eq([]); }); }); describe("when burning more than balance", function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); }); it("should revert", async function () { - await expect(vault.redeem((await vault.balanceOf(deployerAddress)).add("1"))).to.be.reverted; + await expect(vault.redeem((await vault.balanceOf(deployerAddress)) + 1n)).to.be.reverted; await expect(vault.redeem(await vault.balanceOf(deployerAddress))).not.to.be.reverted; }); }); describe("when vault has only underlying balance", function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); bal = await vault.balanceOf(deployerAddress); @@ -543,20 +562,20 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("200")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("200")]); await vault.redeem(bal); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("100")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("100")]); }); it("should burn users notes", async function () { - await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); + await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal * -1n]); + expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100") * 1000000n); }); it("should return redemption amounts", async function () { - const redemptionAmts = await vault.callStatic.redeem(bal); + const redemptionAmts = await vault.redeem.staticCall(bal); expect(redemptionAmts.length).to.eq(1); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); + expect(redemptionAmts[0].token).to.eq(collateralToken.target); expect(redemptionAmts[0].amount).to.eq(toFixedPtAmt("100")); }); }); @@ -564,11 +583,11 @@ describe("RolloverVault", function () { describe("when vault has only deployed balance", function () { let bal: BigNumber; beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); await vault.deploy(); @@ -596,13 +615,13 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], ["0", toFixedPtAmt("40"), toFixedPtAmt("160")], ); await vault.redeem(bal); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], ["0", toFixedPtAmt("20"), toFixedPtAmt("80")], @@ -610,18 +629,18 @@ describe("RolloverVault", function () { }); it("should burn users notes", async function () { - await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); + await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal * -1n]); + expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100") * 1000000n); }); it("should return redemption amounts", async function () { - const redemptionAmts = await vault.callStatic.redeem(bal); + const redemptionAmts = await vault.redeem.staticCall(bal); expect(redemptionAmts.length).to.eq(3); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); + expect(redemptionAmts[0].token).to.eq(collateralToken.target); expect(redemptionAmts[0].amount).to.eq(0); - expect(redemptionAmts[1].token).to.eq(reserveTranches[0].address); + expect(redemptionAmts[1].token).to.eq(reserveTranches[0].target); expect(redemptionAmts[1].amount).to.eq(toFixedPtAmt("20")); - expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].address); + expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].target); expect(redemptionAmts[2].amount).to.eq(toFixedPtAmt("80")); }); }); @@ -629,17 +648,17 @@ describe("RolloverVault", function () { describe("when vault has a combination of balances (full balance redemption)", function () { let redemptionAmts: [string, BigNumber][]; beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("20")); + await collateralToken.transfer(vault.target, toFixedPtAmt("20")); - redemptionAmts = await vault.callStatic.redeem(await vault.balanceOf(deployerAddress)); + redemptionAmts = await vault.redeem.staticCall(await vault.balanceOf(deployerAddress)); bal = await vault.balanceOf(deployerAddress); }); @@ -668,13 +687,13 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("20"), toFixedPtAmt("40"), toFixedPtAmt("160")], ); await vault.redeem(bal); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("10"), toFixedPtAmt("20"), toFixedPtAmt("80")], @@ -682,34 +701,34 @@ describe("RolloverVault", function () { }); it("should burn users notes", async function () { - await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); + await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal * -1n]); + expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100") * 1000000n); }); it("should return redemption amounts", async function () { expect(redemptionAmts.length).to.eq(3); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); + expect(redemptionAmts[0].token).to.eq(collateralToken.target); expect(redemptionAmts[0].amount).to.eq(toFixedPtAmt("10")); - expect(redemptionAmts[1].token).to.eq(reserveTranches[0].address); + expect(redemptionAmts[1].token).to.eq(reserveTranches[0].target); expect(redemptionAmts[1].amount).to.eq(toFixedPtAmt("20")); - expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].address); + expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].target); expect(redemptionAmts[2].amount).to.eq(toFixedPtAmt("80")); }); }); describe("when vault has a combination of balances (partial balance redemption)", function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("20")); + await collateralToken.transfer(vault.target, toFixedPtAmt("20")); - bal = toFixedPtAmt("50").mul("1000000"); + bal = toFixedPtAmt("50") * 1000000n; }); it("should transfer assets", async function () { @@ -737,13 +756,13 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("20"), toFixedPtAmt("40"), toFixedPtAmt("160")], ); await vault.redeem(bal); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("15"), toFixedPtAmt("30"), toFixedPtAmt("120")], @@ -751,37 +770,47 @@ describe("RolloverVault", function () { }); it("should burn users notes", async function () { - await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); + await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal * -1n]); + expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100") * 1000000n); }); it("should return redemption amounts", async function () { - const redemptionAmts = await vault.callStatic.redeem(bal); + const redemptionAmts = await vault.redeem.staticCall(bal); expect(redemptionAmts.length).to.eq(3); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); + expect(redemptionAmts[0].token).to.eq(collateralToken.target); expect(redemptionAmts[0].amount).to.eq(toFixedPtAmt("5")); - expect(redemptionAmts[1].token).to.eq(reserveTranches[0].address); + expect(redemptionAmts[1].token).to.eq(reserveTranches[0].target); expect(redemptionAmts[1].amount).to.eq(toFixedPtAmt("10")); - expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].address); + expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].target); expect(redemptionAmts[2].amount).to.eq(toFixedPtAmt("40")); }); }); describe("when fee > 0", function () { beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); + await collateralToken.approve(vault.target, toFixedPtAmt("100")); await vault.deposit(toFixedPtAmt("100")); await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); + await collateralToken.connect(otherUser).approve(vault.target, toFixedPtAmt("100")); await vault.connect(otherUser).deposit(toFixedPtAmt("100")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("20")); - - bal = toFixedPtAmt("50").mul("1000000"); + await collateralToken.transfer(vault.target, toFixedPtAmt("20")); - await feePolicy.computeVaultBurnFeePerc.returns(toPercFixedPtAmt("0.1")); + bal = toFixedPtAmt("50") * 1000000n; + await feePolicy.clearMockMethod("computeDeviationRatio((uint256,uint256,uint256))"); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("600"), toFixedPtAmt("220"), "200"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockCall( + "computeDeviationRatio((uint256,uint256,uint256))", + [[toFixedPtAmt("600"), toFixedPtAmt("165"), "200"]], + [toPercFixedPtAmt("1")], + ); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); }); it("should transfer assets", async function () { @@ -809,13 +838,13 @@ describe("RolloverVault", function () { }); it("should update vault", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("20"), toFixedPtAmt("40"), toFixedPtAmt("160")], ); await vault.redeem(bal); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, reserveTranches[0], rolloverInTranches[1]], [toFixedPtAmt("15.5"), toFixedPtAmt("31"), toFixedPtAmt("124")], @@ -823,85 +852,20 @@ describe("RolloverVault", function () { }); it("should burn users notes", async function () { - await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); + await expect(() => vault.redeem(bal)).to.changeTokenBalances(vault, [deployer], [bal * -1n]); + expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100") * 1000000n); }); it("should return redemption amounts", async function () { - const redemptionAmts = await vault.callStatic.redeem(bal); + const redemptionAmts = await vault.redeem.staticCall(bal); expect(redemptionAmts.length).to.eq(3); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); + expect(redemptionAmts[0].token).to.eq(collateralToken.target); expect(redemptionAmts[0].amount).to.eq(toFixedPtAmt("4.5")); - expect(redemptionAmts[1].token).to.eq(reserveTranches[0].address); + expect(redemptionAmts[1].token).to.eq(reserveTranches[0].target); expect(redemptionAmts[1].amount).to.eq(toFixedPtAmt("9")); - expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].address); + expect(redemptionAmts[2].token).to.eq(rolloverInTranches[1].target); expect(redemptionAmts[2].amount).to.eq(toFixedPtAmt("36")); }); }); }); - - describe("#recoverAndRedeem", function () { - let bal: BigNumber; - beforeEach(async function () { - await collateralToken.approve(vault.address, toFixedPtAmt("100")); - await vault.deposit(toFixedPtAmt("100")); - - await collateralToken.transfer(otherUserAddress, toFixedPtAmt("100")); - await collateralToken.connect(otherUser).approve(vault.address, toFixedPtAmt("100")); - await vault.connect(otherUser).deposit(toFixedPtAmt("100")); - - await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("20")); - - await advancePerpQueueUpToBondMaturity(perp, await bondAt(await perp.callStatic.getDepositBond())); - bal = toFixedPtAmt("50").mul("1000000"); - }); - - it("should transfer assets", async function () { - await expect(() => vault.recoverAndRedeem(bal)).to.changeTokenBalances( - collateralToken, - [deployer, vault], - [toFixedPtAmt("55"), toFixedPtAmt("145")], - ); - }); - - it("should transfer assets", async function () { - await expect(() => vault.recoverAndRedeem(bal)).to.changeTokenBalances( - reserveTranches[0], - [deployer, vault], - [toFixedPtAmt("0"), toFixedPtAmt("-40")], - ); - }); - - it("should transfer assets", async function () { - await expect(() => vault.recoverAndRedeem(bal)).to.changeTokenBalances( - rolloverInTranches[1], - [deployer, vault], - [toFixedPtAmt("0"), toFixedPtAmt("-160")], - ); - }); - - it("should update vault", async function () { - await checkVaultAssetComposition( - vault, - [collateralToken, reserveTranches[0], rolloverInTranches[1]], - [toFixedPtAmt("20"), toFixedPtAmt("40"), toFixedPtAmt("160")], - ); - await vault.recoverAndRedeem(bal); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("165")]); - }); - - it("should burn users notes", async function () { - await expect(() => vault.recoverAndRedeem(bal)).to.changeTokenBalances(vault, [deployer], [bal.mul("-1")]); - expect(await vault.balanceOf(otherUserAddress)).to.eq(toFixedPtAmt("100").mul("1000000")); - }); - - it("should return redemption amounts", async function () { - await perp.updateState(); - const redemptionAmts = await vault.callStatic.recoverAndRedeem(bal); - expect(redemptionAmts.length).to.eq(1); - expect(redemptionAmts[0].token).to.eq(collateralToken.address); - expect(redemptionAmts[0].amount).to.eq(toFixedPtAmt("55")); - }); - }); }); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_pair_ops.ts b/spot-contracts/test/rollover-vault/RolloverVault_pair_ops.ts new file mode 100644 index 00000000..ca7e6714 --- /dev/null +++ b/spot-contracts/test/rollover-vault/RolloverVault_pair_ops.ts @@ -0,0 +1,532 @@ +import { expect } from "chai"; +import { network, ethers, upgrades } from "hardhat"; +import { Contract, Signer } from "ethers"; + +import { + setupCollateralToken, + mintCollteralToken, + setupBondFactory, + depositIntoBond, + bondAt, + getTranches, + toFixedPtAmt, + toPercFixedPtAmt, + getDepositBond, + advancePerpQueue, + advancePerpQueueToBondMaturity, + checkPerpComposition, + checkVaultComposition, + DMock, +} from "../helpers"; + +let vault: Contract; +let perp: Contract; +let bondFactory: Contract; +let collateralToken: Contract; +let issuer: Contract; +let feePolicy: Contract; +let deployer: Signer; +let reserveTranches: Contract[][] = []; +let remainingJuniorTranches: Contract[][] = []; +let currentBondIn: Contract; +let currentTranchesIn: Contract[]; + +describe("RolloverVault", function () { + beforeEach(async function () { + await network.provider.send("hardhat_reset"); + + const accounts = await ethers.getSigners(); + deployer = accounts[0]; + + bondFactory = await setupBondFactory(); + ({ collateralToken } = await setupCollateralToken("Bitcoin", "BTC")); + + const BondIssuer = await ethers.getContractFactory("BondIssuer"); + issuer = await upgrades.deployProxy( + BondIssuer.connect(deployer), + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], + { + initializer: "init(address,address,uint256,uint256[],uint256,uint256)", + }, + ); + + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); + + const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); + perp = await upgrades.deployProxy( + PerpetualTranche.connect(deployer), + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], + { + initializer: "init(string,string,address,address,address)", + }, + ); + await perp.updateTolerableTrancheMaturity(1200, 4800); + await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); + + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); + + reserveTranches = []; + remainingJuniorTranches = []; + for (let i = 0; i < 4; i++) { + const bond = await getDepositBond(perp); + const tranches = await getTranches(bond); + await depositIntoBond(bond, toFixedPtAmt("1200"), deployer); + + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); + + reserveTranches.push(tranches[0]); + remainingJuniorTranches.push(tranches[1]); + await advancePerpQueue(perp, 1200); + } + + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3)], + [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], + ); + await checkVaultComposition(vault, [collateralToken], [0]); + expect(await vault.assetCount()).to.eq(1); + + await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); + currentTranchesIn = await getTranches(currentBondIn); + + await collateralToken.approve(vault.target, toFixedPtAmt("10000")); + await perp.approve(vault.target, toFixedPtAmt("10000")); + + await vault.deposit(toFixedPtAmt("1000")); + await vault.deploy(); + await vault.deposit(toFixedPtAmt("1000")); + + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("1200"), toFixedPtAmt("800")], + ); + expect(await vault.assetCount()).to.eq(2); + }); + + afterEach(async function () { + await network.provider.send("hardhat_reset"); + }); + + describe("#mint2", function () { + describe("when dr = 1", function () { + beforeEach(async function () { + await feePolicy.mockMethod("computeDRNormSeniorTR(uint256)", [toPercFixedPtAmt("0.25")]); + }); + + it("should compute amounts", async function () { + const r = await vault.mint2.staticCall(toFixedPtAmt("100")); + expect(r[0]).to.eq(toFixedPtAmt("25")); + expect(r[1]).to.eq(toFixedPtAmt("75") * 1000000n); + }); + + it("should transfer underlying", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + collateralToken, + [deployer], + [toFixedPtAmt("-100")], + ); + }); + + it("should mint perps", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("25")], + ); + }); + + it("should mint vault notes", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("75") * 1000000n], + ); + }); + + it("should increase tvl", async function () { + await vault.mint2(toFixedPtAmt("100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2075")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("825")); + }); + + it("should have the updated composition", async function () { + await vault.mint2(toFixedPtAmt("100")); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("225")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("1175"), toFixedPtAmt("900")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.mint2(toFixedPtAmt("100")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("1175")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("900")); + }); + }); + + describe("when dr > 1", function () { + beforeEach(async function () { + await feePolicy.mockMethod("computeDRNormSeniorTR(uint256)", [toPercFixedPtAmt("0.25")]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1.25")]); + await vault.deposit(toFixedPtAmt("1000")); + }); + + it("should compute amounts", async function () { + const r = await vault.mint2.staticCall(toFixedPtAmt("100")); + expect(r[0]).to.eq(toFixedPtAmt("25")); + expect(r[1]).to.eq(toFixedPtAmt("75") * 1000000n); + }); + + it("should transfer underlying", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + collateralToken, + [deployer], + [toFixedPtAmt("-100")], + ); + }); + + it("should mint perps", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("25")], + ); + }); + + it("should mint vault notes", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("75") * 1000000n], + ); + }); + + it("should increase tvl", async function () { + await vault.mint2(toFixedPtAmt("100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("3075")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("825")); + }); + + it("should have the updated composition", async function () { + await vault.mint2(toFixedPtAmt("100")); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("225")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("2175"), toFixedPtAmt("900")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.mint2(toFixedPtAmt("100")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("2175")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("900")); + }); + }); + + describe("when dr < 1", function () { + beforeEach(async function () { + await feePolicy.mockMethod("computeDRNormSeniorTR(uint256)", [toPercFixedPtAmt("0.25")]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("0.75")]); + await vault.redeem(toFixedPtAmt("500") * 1000000n); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1500")); + }); + + it("should compute amounts", async function () { + const r = await vault.mint2.staticCall(toFixedPtAmt("100")); + expect(r[0]).to.eq(toFixedPtAmt("25")); + expect(r[1]).to.eq(toFixedPtAmt("75") * 1000000n); + }); + + it("should transfer underlying", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + collateralToken, + [deployer], + [toFixedPtAmt("-100")], + ); + }); + + it("should mint perps", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("25")], + ); + }); + + it("should mint vault notes", async function () { + await expect(() => vault.mint2(toFixedPtAmt("100"))).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("75") * 1000000n], + ); + }); + + it("should increase tvl", async function () { + await vault.mint2(toFixedPtAmt("100")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1575")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("825")); + }); + + it("should have the updated composition", async function () { + await vault.mint2(toFixedPtAmt("100")); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("225")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("875"), toFixedPtAmt("700")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.mint2(toFixedPtAmt("100")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("875")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("700")); + }); + }); + }); + + describe("#redeem2", function () { + describe("when redeeming proportionally", function () { + it("should compute amounts", async function () { + const r = await vault.redeem2.staticCall(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n); + + expect(r[0]).to.eq(toFixedPtAmt("20")); + expect(r[1]).to.eq(toFixedPtAmt("50") * 1000000n); + + expect(r[2][0][0]).to.eq(collateralToken.target); + expect(r[2][0][1]).to.eq(toFixedPtAmt("30")); + + expect(r[2][1][0]).to.eq(reserveTranches[3].target); + expect(r[2][1][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][2][0]).to.eq(reserveTranches[1].target); + expect(r[2][2][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][3][0]).to.eq(reserveTranches[2].target); + expect(r[2][3][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][4][0]).to.eq(currentTranchesIn[0].target); + expect(r[2][4][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][5][0]).to.eq(currentTranchesIn[1].target); + expect(r[2][5][1]).to.eq(toFixedPtAmt("20")); + }); + + it("should burn perps", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n)).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("-20")], + ); + }); + + it("should burn vault notes", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n)).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("-50") * 1000000n], + ); + }); + + it("should decrease tvl", async function () { + await vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1950")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("780")); + }); + + it("should have the updated composition", async function () { + await vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("1170"), toFixedPtAmt("780")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("50") * 1000000n); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("1170")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("780")); + }); + }); + + describe("when redeeming more perps", function () { + it("should compute amounts", async function () { + const r = await vault.redeem2.staticCall(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n); + + expect(r[0]).to.eq(toFixedPtAmt("20")); + expect(r[1]).to.eq(toFixedPtAmt("50") * 1000000n); + + expect(r[2][0][0]).to.eq(collateralToken.target); + expect(r[2][0][1]).to.eq(toFixedPtAmt("30")); + + expect(r[2][1][0]).to.eq(reserveTranches[3].target); + expect(r[2][1][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][2][0]).to.eq(reserveTranches[1].target); + expect(r[2][2][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][3][0]).to.eq(reserveTranches[2].target); + expect(r[2][3][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][4][0]).to.eq(currentTranchesIn[0].target); + expect(r[2][4][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][5][0]).to.eq(currentTranchesIn[1].target); + expect(r[2][5][1]).to.eq(toFixedPtAmt("20")); + }); + + it("should burn perps", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n)).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("-20")], + ); + }); + + it("should burn vault notes", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n)).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("-50") * 1000000n], + ); + }); + + it("should decrease tvl", async function () { + await vault.redeem2(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1950")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("780")); + }); + + it("should have the updated composition", async function () { + await vault.redeem2(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("1170"), toFixedPtAmt("780")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.redeem2(toFixedPtAmt("100"), toFixedPtAmt("50") * 1000000n); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("1170")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("780")); + }); + }); + + describe("when redeeming more vault notes", function () { + it("should compute amounts", async function () { + const r = await vault.redeem2.staticCall(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n); + + expect(r[0]).to.eq(toFixedPtAmt("20")); + expect(r[1]).to.eq(toFixedPtAmt("50") * 1000000n); + + expect(r[2][0][0]).to.eq(collateralToken.target); + expect(r[2][0][1]).to.eq(toFixedPtAmt("30")); + + expect(r[2][1][0]).to.eq(reserveTranches[3].target); + expect(r[2][1][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][2][0]).to.eq(reserveTranches[1].target); + expect(r[2][2][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][3][0]).to.eq(reserveTranches[2].target); + expect(r[2][3][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][4][0]).to.eq(currentTranchesIn[0].target); + expect(r[2][4][1]).to.eq(toFixedPtAmt("5")); + + expect(r[2][5][0]).to.eq(currentTranchesIn[1].target); + expect(r[2][5][1]).to.eq(toFixedPtAmt("20")); + }); + + it("should burn perps", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n)).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("-20")], + ); + }); + + it("should burn vault notes", async function () { + await expect(() => vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n)).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("-50") * 1000000n], + ); + }); + + it("should decrease tvl", async function () { + await vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1950")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("780")); + }); + + it("should have the updated composition", async function () { + await vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n); + await checkPerpComposition( + perp, + [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], + [toFixedPtAmt("0"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195"), toFixedPtAmt("195")], + ); + await checkVaultComposition( + vault, + [collateralToken, currentTranchesIn[1]], + [toFixedPtAmt("1170"), toFixedPtAmt("780")], + ); + }); + + it("should sync vault assets", async function () { + const tx = vault.redeem2(toFixedPtAmt("20"), toFixedPtAmt("100") * 1000000n); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("1170")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("780")); + }); + }); + }); +}); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_rebalance.ts b/spot-contracts/test/rollover-vault/RolloverVault_rebalance.ts new file mode 100644 index 00000000..eacbda7d --- /dev/null +++ b/spot-contracts/test/rollover-vault/RolloverVault_rebalance.ts @@ -0,0 +1,373 @@ +import { expect } from "chai"; +import { network, ethers, upgrades } from "hardhat"; +import { Contract, Signer } from "ethers"; + +import { + setupCollateralToken, + mintCollteralToken, + setupBondFactory, + depositIntoBond, + bondAt, + getTranches, + toFixedPtAmt, + getDepositBond, + advancePerpQueue, + advancePerpQueueToBondMaturity, + checkPerpComposition, + checkVaultComposition, + DMock, + toPercFixedPtAmt, + TimeHelpers, +} from "../helpers"; + +let vault: Contract; +let perp: Contract; +let bondFactory: Contract; +let collateralToken: Contract; +let issuer: Contract; +let feePolicy: Contract; +let deployer: Signer; +const reserveSrTranches: Contract[][] = []; +const reserveJrTranches: Contract[][] = []; + +describe("RolloverVault", function () { + beforeEach(async function () { + await network.provider.send("hardhat_reset"); + + const accounts = await ethers.getSigners(); + deployer = accounts[0]; + + bondFactory = await setupBondFactory(); + ({ collateralToken } = await setupCollateralToken("Bitcoin", "BTC")); + + const BondIssuer = await ethers.getContractFactory("BondIssuer"); + issuer = await upgrades.deployProxy( + BondIssuer.connect(deployer), + [bondFactory.target, collateralToken.target, 4 * 86400, [200, 800], 86400, 0], + { + initializer: "init(address,address,uint256,uint256[],uint256,uint256)", + }, + ); + + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); + + const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); + perp = await upgrades.deployProxy( + PerpetualTranche.connect(deployer), + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], + { + initializer: "init(string,string,address,address,address)", + }, + ); + + await perp.updateTolerableTrancheMaturity(86400, 4 * 86400); + await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); + + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); + + for (let i = 0; i < 4; i++) { + const bond = await getDepositBond(perp); + const tranches = await getTranches(bond); + await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); + + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); + + reserveSrTranches.push(tranches[0]); + reserveJrTranches.push(tranches[1]); + await advancePerpQueue(perp, 86400); + } + + await checkPerpComposition( + perp, + [collateralToken, ...reserveSrTranches.slice(-3)], + [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], + ); + + await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); + await collateralToken.approve(vault.target, toFixedPtAmt("100000")); + const currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); + const currentTranchesIn = await getTranches(currentBondIn); + await vault.deposit(toFixedPtAmt("2000")); + await vault.deploy(); + + await checkVaultComposition( + vault, + [collateralToken, reserveSrTranches[1], currentTranchesIn[1]], + [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("1600")], + ); + expect(await vault.assetCount()).to.eq(3); + await TimeHelpers.increaseTime(86401); + + await feePolicy.mockMethod("protocolSharePerc()", [0n]); + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [0n]); + await feePolicy.mockMethod("protocolFeeCollector()", [await deployer.getAddress()]); + await feePolicy.mockMethod("rebalanceFreqSec()", [86400]); + }); + + afterEach(async function () { + await network.provider.send("hardhat_reset"); + }); + + describe("#rebalance()", function () { + describe("when system is paused", function () { + it("should revert", async function () { + await vault.pause(); + await expect(vault.rebalance()).to.be.revertedWith("Pausable: paused"); + }); + }); + + describe("when rebalance is paused", function () { + it("should revert", async function () { + await vault.pauseRebalance(); + await expect(vault.rebalance()).to.be.revertedWithCustomError(vault, "LastRebalanceTooRecent"); + }); + }); + + describe("when invoked too soon", function () { + it("should revert", async function () { + await vault.rebalance(); + await expect(vault.rebalance()).to.be.revertedWithCustomError(vault, "LastRebalanceTooRecent"); + await TimeHelpers.increaseTime(86401); + await expect(vault.rebalance()).to.not.be.reverted; + }); + }); + + describe("no-change", function () { + beforeEach(async function () { + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("0")]); + }); + it("should transfer value to the vault (by minting and melding perps)", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2000000000")); + }); + }); + + describe("no-change with protocol fee", function () { + beforeEach(async function () { + await feePolicy.mockMethod("protocolSharePerc()", [toPercFixedPtAmt("0.01")]); + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("0")]); + }); + it("should transfer value to the vault (by minting and melding perps)", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("808.080808080808080808")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2020202020.202020202020202020")); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("8.080808080808080808")], + ); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("20202020.202020202020202020")], + ); + }); + }); + + describe("perp debasement", function () { + beforeEach(async function () { + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("-10")]); + }); + it("should transfer value to the vault (by minting and melding perps)", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("790")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2000000000")); + }); + it("should update the vault balance (after melding)", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances(collateralToken, [vault], [toFixedPtAmt("25")]); + }); + it("should sync token balances", async function () { + const tx = vault.rebalance(); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("225")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(perp.target, toFixedPtAmt("0")); + }); + }); + + describe("perp debasement with protocol fee", function () { + beforeEach(async function () { + await feePolicy.mockMethod("protocolSharePerc()", [toPercFixedPtAmt("0.01")]); + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("-10")]); + }); + it("should transfer value to the vault (by minting and melding perps)", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("790")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("808.080808080808080808")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2020202020.202020202020202020")); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("8.080808080808080808")], + ); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("20202020.202020202020202020")], + ); + }); + it("should update the vault balance (after melding)", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances(collateralToken, [vault], [toFixedPtAmt("25")]); + }); + it("should sync token balances", async function () { + const tx = vault.rebalance(); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("225")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(perp.target, toFixedPtAmt("0")); + }); + }); + + describe("perp enrichment", function () { + let depositBond: Contract, depositTranches: Contract[]; + beforeEach(async function () { + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("25")]); + await perp.updateState(); + depositBond = await getDepositBond(perp); + depositTranches = await getTranches(depositBond); + }); + + it("should transfer value to perp", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("825")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1975")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2000000000")); + }); + + it("should tranche using deposit bond", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + collateralToken, + [vault, depositBond.target], + [toFixedPtAmt("-125"), toFixedPtAmt("125")], + ); + }); + it("should transfer seniors from vault to perp", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + depositTranches[0], + [vault, perp], + [toFixedPtAmt("0"), toFixedPtAmt("25")], + ); + }); + it("should not change perp supply", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + await vault.rebalance(); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + }); + it("should sync token balances", async function () { + const tx = vault.rebalance(); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("75")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(depositTranches[1].target, toFixedPtAmt("100")); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTranches[0].target, toFixedPtAmt("25")); + }); + }); + + describe("perp enrichment with protocol fee", function () { + let depositBond: Contract, depositTranches: Contract[]; + beforeEach(async function () { + await feePolicy.mockMethod("protocolSharePerc()", [toPercFixedPtAmt("0.01")]); + await feePolicy.mockMethod("computeRebalanceAmount((uint256,uint256,uint256))", [toFixedPtAmt("25")]); + await perp.updateState(); + depositBond = await getDepositBond(perp); + depositTranches = await getTranches(depositBond); + }); + + it("should transfer value to perp", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("800")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); + await expect(() => vault.rebalance()).to.changeTokenBalances(perp, [vault], [toFixedPtAmt("0")]); + expect(await perp.getTVL.staticCall()).to.eq(toFixedPtAmt("825")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("1975")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("808.080808080808080808")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2020202020.202020202020202020")); + }); + + it("should tranche using deposit bond", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + collateralToken, + [vault, depositBond.target], + [toFixedPtAmt("-125"), toFixedPtAmt("125")], + ); + }); + it("should transfer seniors from vault to perp", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + depositTranches[0], + [vault, perp], + [toFixedPtAmt("0"), toFixedPtAmt("25")], + ); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + perp, + [deployer], + [toFixedPtAmt("8.080808080808080808")], + ); + }); + it("should pay the protocol fee", async function () { + await expect(() => vault.rebalance()).to.changeTokenBalances( + vault, + [deployer], + [toFixedPtAmt("20202020.202020202020202020")], + ); + }); + it("should mint notes as fees", async function () { + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2000000000")); + await vault.rebalance(); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("808.080808080808080808")); + expect(await vault.totalSupply()).to.eq(toFixedPtAmt("2020202020.202020202020202020")); + }); + it("should sync token balances", async function () { + const tx = vault.rebalance(); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("75")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(depositTranches[1].target, toFixedPtAmt("100")); + await expect(tx).to.emit(perp, "ReserveSynced").withArgs(depositTranches[0].target, toFixedPtAmt("25")); + }); + }); + }); +}); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_recover.ts b/spot-contracts/test/rollover-vault/RolloverVault_recover.ts index e3d97785..484f6753 100644 --- a/spot-contracts/test/rollover-vault/RolloverVault_recover.ts +++ b/spot-contracts/test/rollover-vault/RolloverVault_recover.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; import { Contract, Signer } from "ethers"; -import { smock } from "@defi-wonderland/smock"; import { setupCollateralToken, @@ -17,10 +16,11 @@ import { advancePerpQueueUpToBondMaturity, advancePerpQueueToBondMaturity, advancePerpQueueToRollover, - checkReserveComposition, - checkVaultAssetComposition, + checkPerpComposition, + checkVaultComposition, + DMock, + toPercFixedPtAmt, } from "../helpers"; -use(smock.matchers); let vault: Contract; let perp: Contract; @@ -45,21 +45,22 @@ describe("RolloverVault", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 4800, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.computePerpRolloverFeePerc.returns("0"); - await feePolicy.decimals.returns(8); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -68,10 +69,19 @@ describe("RolloverVault", function () { await perp.updateTolerableTrancheMaturity(1200, 4800); await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); reserveTranches = []; for (let i = 0; i < 4; i++) { @@ -79,25 +89,25 @@ describe("RolloverVault", function () { const tranches = await getTranches(bond); await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); reserveTranches.push(tranches[0]); await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3)], [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - rolloverInBond = await bondAt(await perp.callStatic.getDepositBond()); + rolloverInBond = await bondAt(await perp.getDepositBond.staticCall()); await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); - await collateralToken.approve(vault.address, toFixedPtAmt("1")); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); - await checkVaultAssetComposition(vault, [collateralToken], ["0"]); + await checkVaultComposition(vault, [collateralToken], ["0"]); expect(await vault.assetCount()).to.eq(1); }); @@ -118,13 +128,13 @@ describe("RolloverVault", function () { let currentBondIn: Contract, currentTranchesIn: Contract[]; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -134,7 +144,7 @@ describe("RolloverVault", function () { describe("when its not mature", function () { it("should be a no-op", async function () { await expect(vault["recover()"]()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -149,12 +159,12 @@ describe("RolloverVault", function () { it("should recover", async function () { await expect(vault["recover()"]()).not.to.be.reverted; expect(await vault.assetCount()).to.eq(1); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("10")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("10")]); }); it("should sync assets", async function () { const tx = vault["recover()"](); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, "0"); }); }); }); @@ -163,13 +173,13 @@ describe("RolloverVault", function () { let currentBondIn: Contract, currentTranchesIn: Contract[], newBondIn: Contract, newTranchesIn: Contract[]; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -180,7 +190,7 @@ describe("RolloverVault", function () { describe("when no redemption", function () { it("should be a no-op", async function () { await expect(vault["recover()"]()).not.to.be.reverted; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -196,30 +206,30 @@ describe("RolloverVault", function () { it("should recover", async function () { await expect(vault["recover()"]()).not.to.be.reverted; expect(await vault.assetCount()).to.eq(1); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("10")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("10")]); }); it("should sync assets", async function () { const tx = vault["recover()"](); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, "0"); }); }); describe("when immature redemption", function () { beforeEach(async function () { await depositIntoBond(currentBondIn, toFixedPtAmt("1000"), deployer); - await currentTranchesIn[0].transfer(vault.address, toFixedPtAmt("100")); + await currentTranchesIn[0].transfer(vault.target, toFixedPtAmt("100")); await advancePerpQueueToRollover(perp, currentBondIn); - newBondIn = await bondAt(await perp.callStatic.getDepositBond()); + newBondIn = await bondAt(await perp.getDepositBond.staticCall()); newTranchesIn = await getTranches(newBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("9998")); + await collateralToken.transfer(vault.target, toFixedPtAmt("9998")); await vault.deploy(); expect(await vault.assetCount()).to.eq(3); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[0], newTranchesIn[1]], [toFixedPtAmt("6808"), toFixedPtAmt("100"), toFixedPtAmt("3200")], @@ -228,12 +238,12 @@ describe("RolloverVault", function () { describe("without reminder", function () { beforeEach(async function () { - await currentTranchesIn[1].transfer(vault.address, toFixedPtAmt("400")); + await currentTranchesIn[1].transfer(vault.target, toFixedPtAmt("400")); }); it("should recover", async function () { await expect(vault["recover()"]()).not.to.be.reverted; expect(await vault.assetCount()).to.eq(2); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("7308"), toFixedPtAmt("3200")], @@ -241,20 +251,20 @@ describe("RolloverVault", function () { }); it("should sync assets", async function () { const tx = vault["recover()"](); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("7308")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, toFixedPtAmt("3200")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].address, toFixedPtAmt("0")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("7308")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, toFixedPtAmt("3200")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].target, toFixedPtAmt("0")); }); }); describe("with reminder", function () { beforeEach(async function () { - await currentTranchesIn[1].transfer(vault.address, toFixedPtAmt("100")); + await currentTranchesIn[1].transfer(vault.target, toFixedPtAmt("100")); }); it("should recover", async function () { await expect(vault["recover()"]()).not.to.be.reverted; expect(await vault.assetCount()).to.eq(3); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[0], newTranchesIn[1]], [toFixedPtAmt("6933"), toFixedPtAmt("75"), toFixedPtAmt("3200")], @@ -262,9 +272,9 @@ describe("RolloverVault", function () { }); it("should sync assets", async function () { const tx = vault["recover()"](); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("6933")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].address, toFixedPtAmt("75")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, toFixedPtAmt("3200")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("6933")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].target, toFixedPtAmt("75")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, toFixedPtAmt("3200")); }); }); }); @@ -275,7 +285,7 @@ describe("RolloverVault", function () { describe("when no asset is deployed", function () { it("should revert", async function () { await vault["recover()"](); - await expect(vault["recover(address)"](collateralToken.address)).to.be.revertedWithCustomError( + await expect(vault["recover(address)"](collateralToken.target)).to.be.revertedWithCustomError( vault, "UnexpectedAsset", ); @@ -287,13 +297,13 @@ describe("RolloverVault", function () { let currentBondIn: Contract, currentTranchesIn: Contract[]; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -303,7 +313,7 @@ describe("RolloverVault", function () { describe("when address is not valid", function () { it("should be reverted", async function () { - await expect(vault["recover(address)"](collateralToken.address)).to.be.revertedWithCustomError( + await expect(vault["recover(address)"](collateralToken.target)).to.be.revertedWithCustomError( vault, "UnexpectedAsset", ); @@ -313,14 +323,14 @@ describe("RolloverVault", function () { describe("when belongs to a malicious tranche", function () { it("should be reverted", async function () { const maliciousBond = await createBondWithFactory(bondFactory, collateralToken, [1, 999], 100000000000); - await collateralToken.approve(maliciousBond.address, toFixedPtAmt("1")); + await collateralToken.approve(maliciousBond.target, toFixedPtAmt("1")); await maliciousBond.deposit(toFixedPtAmt("1")); const maliciousTranches = await getTranches(maliciousBond); await maliciousTranches[1].transfer( - vault.address, + vault.target, maliciousTranches[1].balanceOf(await deployer.getAddress()), ); - await expect(vault["recover(address)"](maliciousTranches[1].address)).to.be.revertedWithCustomError( + await expect(vault["recover(address)"](maliciousTranches[1].target)).to.be.revertedWithCustomError( vault, "UnexpectedAsset", ); @@ -329,8 +339,8 @@ describe("RolloverVault", function () { describe("when its not mature", function () { it("should be a no-op", async function () { - await expect(vault["recover(address)"](currentTranchesIn[1].address)).not.to.be.reverted; - await checkVaultAssetComposition( + await expect(vault["recover(address)"](currentTranchesIn[1].target)).not.to.be.reverted; + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -344,14 +354,14 @@ describe("RolloverVault", function () { await advancePerpQueueUpToBondMaturity(perp, currentBondIn); }); it("should recover", async function () { - await expect(vault["recover(address)"](currentTranchesIn[1].address)).not.to.be.reverted; + await expect(vault["recover(address)"](currentTranchesIn[1].target)).not.to.be.reverted; expect(await vault.assetCount()).to.eq(1); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("10")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("10")]); }); it("should sync assets", async function () { - const tx = vault["recover(address)"](currentTranchesIn[1].address); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, "0"); + const tx = vault["recover(address)"](currentTranchesIn[1].target); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, "0"); }); }); }); @@ -360,13 +370,13 @@ describe("RolloverVault", function () { let currentBondIn: Contract, currentTranchesIn: Contract[], newBondIn: Contract, newTranchesIn: Contract[]; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -376,8 +386,8 @@ describe("RolloverVault", function () { describe("when no redemption", function () { it("should be a no-op", async function () { - await expect(vault["recover(address)"](currentTranchesIn[1].address)).not.to.be.reverted; - await checkVaultAssetComposition( + await expect(vault["recover(address)"](currentTranchesIn[1].target)).not.to.be.reverted; + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -391,29 +401,30 @@ describe("RolloverVault", function () { await advancePerpQueueToBondMaturity(perp, currentBondIn); }); it("should recover", async function () { - await expect(vault["recover(address)"](currentTranchesIn[1].address)).not.to.be.reverted; - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("10")]); + await expect(vault["recover(address)"](currentTranchesIn[1].target)).not.to.be.reverted; + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("10")]); expect(await vault.assetCount()).to.eq(1); }); it("should sync assets", async function () { - const tx = vault["recover(address)"](currentTranchesIn[1].address); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, "0"); + const tx = vault["recover(address)"](currentTranchesIn[1].target); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, "0"); }); }); describe("when immature redemption", function () { beforeEach(async function () { await advancePerpQueueToRollover(perp, currentBondIn); + await depositIntoBond(currentBondIn, toFixedPtAmt("10"), deployer); - newBondIn = await bondAt(await perp.callStatic.getDepositBond()); + newBondIn = await bondAt(await perp.getDepositBond.staticCall()); newTranchesIn = await getTranches(newBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("9998")); + await collateralToken.transfer(vault.target, toFixedPtAmt("9998")); await vault.deploy(); expect(await vault.assetCount()).to.eq(2); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("6808"), toFixedPtAmt("3200")], @@ -423,31 +434,31 @@ describe("RolloverVault", function () { describe("without reminder", function () { beforeEach(async function () { await depositIntoBond(newBondIn, toFixedPtAmt("4000"), deployer); - await newTranchesIn[0].transfer(vault.address, toFixedPtAmt("800")); + await newTranchesIn[0].transfer(vault.target, toFixedPtAmt("800")); }); it("should recover", async function () { - await expect(vault["recover(address)"](newTranchesIn[1].address)).not.to.be.reverted; + await expect(vault["recover(address)"](newTranchesIn[1].target)).not.to.be.reverted; expect(await vault.assetCount()).to.eq(1); - await checkVaultAssetComposition(vault, [collateralToken], [toFixedPtAmt("10808")]); + await checkVaultComposition(vault, [collateralToken], [toFixedPtAmt("10808")]); }); it("should sync assets", async function () { - const tx = vault["recover(address)"](newTranchesIn[1].address); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10808")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].address, "0"); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, "0"); + const tx = vault["recover(address)"](newTranchesIn[1].target); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10808")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].target, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, "0"); }); }); describe("with reminder", function () { beforeEach(async function () { await depositIntoBond(newBondIn, toFixedPtAmt("1000"), deployer); - await newTranchesIn[0].transfer(vault.address, toFixedPtAmt("200")); + await newTranchesIn[0].transfer(vault.target, toFixedPtAmt("200")); }); it("should recover", async function () { - await expect(vault["recover(address)"](newTranchesIn[1].address)).not.to.be.reverted; + await expect(vault["recover(address)"](newTranchesIn[1].target)).not.to.be.reverted; expect(await vault.assetCount()).to.eq(2); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("7808"), toFixedPtAmt("2400")], @@ -455,23 +466,23 @@ describe("RolloverVault", function () { }); it("should sync assets", async function () { - const tx = vault["recover(address)"](newTranchesIn[1].address); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("7808")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].address, toFixedPtAmt("0")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, toFixedPtAmt("2400")); + const tx = vault["recover(address)"](newTranchesIn[1].target); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("7808")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].target, toFixedPtAmt("0")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, toFixedPtAmt("2400")); }); }); describe("with dust reminder", function () { beforeEach(async function () { await depositIntoBond(newBondIn, toFixedPtAmt("1000"), deployer); - await newTranchesIn[0].transfer(vault.address, "200000"); + await newTranchesIn[0].transfer(vault.target, "200000"); }); it("should recover", async function () { - await expect(vault["recover(address)"](newTranchesIn[1].address)).not.to.be.reverted; + await expect(vault["recover(address)"](newTranchesIn[1].target)).not.to.be.reverted; expect(await vault.assetCount()).to.eq(2); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("6808.000000000001"), toFixedPtAmt("3199.9999999999992")], @@ -479,31 +490,31 @@ describe("RolloverVault", function () { }); it("should sync assets", async function () { - const tx = vault["recover(address)"](newTranchesIn[1].address); + const tx = vault["recover(address)"](newTranchesIn[1].target); await expect(tx) .to.emit(vault, "AssetSynced") - .withArgs(collateralToken.address, toFixedPtAmt("6808.000000000001")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].address, toFixedPtAmt("0")); + .withArgs(collateralToken.target, toFixedPtAmt("6808.000000000001")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].target, toFixedPtAmt("0")); await expect(tx) .to.emit(vault, "AssetSynced") - .withArgs(newTranchesIn[1].address, toFixedPtAmt("3199.9999999999992")); + .withArgs(newTranchesIn[1].target, toFixedPtAmt("3199.9999999999992")); }); it("should not recover dust when triggered again", async function () { await depositIntoBond(newBondIn, toFixedPtAmt("10000"), deployer); - await newTranchesIn[0].transfer(vault.address, toFixedPtAmt("799.999999999999")); - await vault["recover(address)"](newTranchesIn[1].address); - const tx = vault["recover(address)"](newTranchesIn[1].address); + await newTranchesIn[0].transfer(vault.target, toFixedPtAmt("799.999999999999")); + await vault["recover(address)"](newTranchesIn[1].target); + const tx = vault["recover(address)"](newTranchesIn[1].target); await tx; - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("10807.999999999996"), "3200000"], ); await expect(tx) .to.emit(vault, "AssetSynced") - .withArgs(collateralToken.address, toFixedPtAmt("10807.999999999996")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, "3200000"); + .withArgs(collateralToken.target, toFixedPtAmt("10807.999999999996")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, "3200000"); }); }); }); @@ -512,13 +523,13 @@ describe("RolloverVault", function () { describe("recovering perp", function () { let currentBondIn: Contract, currentTranchesIn: Contract[]; beforeEach(async function () { - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("125")); + await collateralToken.transfer(vault.target, toFixedPtAmt("125")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("25"), toFixedPtAmt("100")], @@ -528,8 +539,8 @@ describe("RolloverVault", function () { describe("when vault has no perps", function () { it("should be a no-op", async function () { - await expect(vault["recover(address)"](perp.address)).not.to.be.reverted; - await checkVaultAssetComposition( + await expect(vault["recover(address)"](perp.target)).not.to.be.reverted; + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("25"), toFixedPtAmt("100")], @@ -540,11 +551,11 @@ describe("RolloverVault", function () { describe("when vault has perps", function () { beforeEach(async function () { - await perp.transfer(vault.address, toFixedPtAmt("100")); + await perp.transfer(vault.target, toFixedPtAmt("100")); }); it("should recover", async function () { - await expect(vault["recover(address)"](perp.address)).not.to.be.reverted; - await checkVaultAssetComposition( + await expect(vault["recover(address)"](perp.target)).not.to.be.reverted; + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3)], [toFixedPtAmt("62.5"), toFixedPtAmt("87.5"), toFixedPtAmt("25"), toFixedPtAmt("25"), toFixedPtAmt("25")], @@ -552,13 +563,13 @@ describe("RolloverVault", function () { expect(await vault.assetCount()).to.eq(5); }); it("should sync assets", async function () { - const tx = vault["recover(address)"](perp.address); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("62.5")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, toFixedPtAmt("87.5")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].address, "0"); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[1].address, toFixedPtAmt("25")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[2].address, toFixedPtAmt("25")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[3].address, toFixedPtAmt("25")); + const tx = vault["recover(address)"](perp.target); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("62.5")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, toFixedPtAmt("87.5")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[0].target, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[1].target, toFixedPtAmt("25")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[2].target, toFixedPtAmt("25")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(reserveTranches[3].target, toFixedPtAmt("25")); }); }); }); @@ -568,13 +579,13 @@ describe("RolloverVault", function () { let currentBondIn: Contract, currentTranchesIn: Contract[], newBondIn: Contract, newTranchesIn: Contract[]; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, rolloverInBond); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("10")); + await collateralToken.transfer(vault.target, toFixedPtAmt("10")); await vault.deploy(); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")], @@ -583,28 +594,24 @@ describe("RolloverVault", function () { await advancePerpQueueToBondMaturity(perp, currentBondIn); - newBondIn = await bondAt(await perp.callStatic.getDepositBond()); + newBondIn = await bondAt(await perp.getDepositBond.staticCall()); newTranchesIn = await getTranches(newBondIn); }); it("should recover", async function () { await expect(vault.recoverAndRedeploy()).not.to.be.reverted; expect(await vault.assetCount()).to.eq(2); - await checkVaultAssetComposition( - vault, - [collateralToken, newTranchesIn[1]], - [toFixedPtAmt("2"), toFixedPtAmt("8")], - ); + await checkVaultComposition(vault, [collateralToken, newTranchesIn[1]], [toFixedPtAmt("2"), toFixedPtAmt("8")]); }); it("should sync assets", async function () { const tx = vault.recoverAndRedeploy(); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("10")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].address, "0"); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].address, toFixedPtAmt("2")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].address, toFixedPtAmt("8")); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].address, "0"); - await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.address, toFixedPtAmt("2")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("10")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(currentTranchesIn[1].target, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].target, toFixedPtAmt("2")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[1].target, toFixedPtAmt("8")); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(newTranchesIn[0].target, "0"); + await expect(tx).to.emit(vault, "AssetSynced").withArgs(collateralToken.target, toFixedPtAmt("2")); }); }); }); diff --git a/spot-contracts/test/rollover-vault/RolloverVault_swap.ts b/spot-contracts/test/rollover-vault/RolloverVault_swap.ts index fa686e38..de666072 100644 --- a/spot-contracts/test/rollover-vault/RolloverVault_swap.ts +++ b/spot-contracts/test/rollover-vault/RolloverVault_swap.ts @@ -1,7 +1,6 @@ -import { expect, use } from "chai"; +import { expect } from "chai"; import { network, ethers, upgrades } from "hardhat"; -import { Contract, Signer, constants, Transaction } from "ethers"; -import { smock } from "@defi-wonderland/smock"; +import { Contract, Signer, Transaction } from "ethers"; import { setupCollateralToken, @@ -15,11 +14,11 @@ import { getDepositBond, advancePerpQueue, advancePerpQueueToBondMaturity, - checkReserveComposition, - checkVaultAssetComposition, + checkPerpComposition, + checkVaultComposition, rebase, + DMock, } from "../helpers"; -use(smock.matchers); let vault: Contract; let perp: Contract; @@ -47,23 +46,22 @@ describe("RolloverVault", function () { const BondIssuer = await ethers.getContractFactory("BondIssuer"); issuer = await upgrades.deployProxy( BondIssuer.connect(deployer), - [bondFactory.address, collateralToken.address, 4800, [200, 800], 1200, 0], + [bondFactory.target, collateralToken.target, 4800, [200, 800], 1200, 0], { initializer: "init(address,address,uint256,uint256[],uint256,uint256)", }, ); - const FeePolicy = await ethers.getContractFactory("FeePolicy"); - feePolicy = await smock.fake(FeePolicy); - await feePolicy.decimals.returns(8); - await feePolicy.computePerpMintFeePerc.returns(0); - await feePolicy.computePerpBurnFeePerc.returns(0); - await feePolicy.computePerpRolloverFeePerc.returns(0); + feePolicy = new DMock(await ethers.getContractFactory("FeePolicy")); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("computeDeviationRatio((uint256,uint256,uint256))", [toPercFixedPtAmt("1")]); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); const PerpetualTranche = await ethers.getContractFactory("PerpetualTranche"); perp = await upgrades.deployProxy( PerpetualTranche.connect(deployer), - ["PerpetualTranche", "PERP", collateralToken.address, issuer.address, feePolicy.address], + ["PerpetualTranche", "PERP", collateralToken.target, issuer.target, feePolicy.target], { initializer: "init(string,string,address,address,address)", }, @@ -71,51 +69,60 @@ describe("RolloverVault", function () { await perp.updateTolerableTrancheMaturity(1200, 4800); await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - const RolloverVault = await ethers.getContractFactory("RolloverVault"); - vault = await upgrades.deployProxy(RolloverVault.connect(deployer)); - await collateralToken.approve(vault.address, toFixedPtAmt("1")); - await vault.init("RolloverVault", "VSHARE", perp.address, feePolicy.address); - await perp.updateVault(vault.address); + const TrancheManager = await ethers.getContractFactory("TrancheManager"); + const trancheManager = await TrancheManager.deploy(); + const RolloverVault = await ethers.getContractFactory("RolloverVault", { + libraries: { + TrancheManager: trancheManager.target, + }, + }); + await upgrades.silenceWarnings(); + vault = await upgrades.deployProxy(RolloverVault.connect(deployer), { + unsafeAllow: ["external-library-linking"], + }); + await collateralToken.approve(vault.target, toFixedPtAmt("1")); + await vault.init("RolloverVault", "VSHARE", perp.target, feePolicy.target); + await perp.updateVault(vault.target); reserveTranches = []; remainingJuniorTranches = []; for (let i = 0; i < 4; i++) { const bond = await getDepositBond(perp); const tranches = await getTranches(bond); - await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); + await depositIntoBond(bond, toFixedPtAmt("1200"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); reserveTranches.push(tranches[0]); remainingJuniorTranches.push(tranches[1]); await advancePerpQueue(perp, 1200); } - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3)], [toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition(vault, [collateralToken], [0]); + await checkVaultComposition(vault, [collateralToken], [0]); expect(await vault.assetCount()).to.eq(1); await mintCollteralToken(collateralToken, toFixedPtAmt("100000"), deployer); - currentBondIn = await bondAt(await perp.callStatic.getDepositBond()); + currentBondIn = await bondAt(await perp.getDepositBond.staticCall()); currentTranchesIn = await getTranches(currentBondIn); - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); await vault.deploy(); - await collateralToken.transfer(vault.address, toFixedPtAmt("1000")); + await collateralToken.transfer(vault.target, toFixedPtAmt("1000")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], ); expect(await vault.assetCount()).to.eq(2); - await collateralToken.approve(vault.address, toFixedPtAmt("10000")); - await perp.approve(vault.address, toFixedPtAmt("10000")); + await collateralToken.approve(vault.target, toFixedPtAmt("10000")); + await perp.approve(vault.target, toFixedPtAmt("10000")); }); afterEach(async function () { @@ -124,14 +131,9 @@ describe("RolloverVault", function () { describe("#swapUnderlyingForPerps", function () { describe("when fee is zero", function () { - beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(0); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(0); - }); - describe("when perp price is 1", function () { it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("100")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); @@ -140,7 +142,7 @@ describe("RolloverVault", function () { }); it("should update vault after swap", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -148,7 +150,7 @@ describe("RolloverVault", function () { await vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("800"), toFixedPtAmt("1200")], @@ -158,11 +160,11 @@ describe("RolloverVault", function () { describe("when perp price > 1", function () { beforeEach(async function () { - await collateralToken.transfer(perp.address, toFixedPtAmt("800")); + await collateralToken.transfer(perp.target, toFixedPtAmt("800")); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("50")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("1600")); @@ -171,7 +173,7 @@ describe("RolloverVault", function () { }); it("should update vault after swap", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -179,7 +181,7 @@ describe("RolloverVault", function () { await vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("800"), toFixedPtAmt("1200")], @@ -192,7 +194,7 @@ describe("RolloverVault", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("200")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("400")); @@ -200,7 +202,7 @@ describe("RolloverVault", function () { expect(s[2].seniorTR).to.eq("200"); }); it("should update vault after swap", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("120"), toFixedPtAmt("800")], @@ -208,7 +210,7 @@ describe("RolloverVault", function () { await vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("120"), toFixedPtAmt("1600")], @@ -222,7 +224,7 @@ describe("RolloverVault", function () { }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("100")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); @@ -231,7 +233,7 @@ describe("RolloverVault", function () { }); it("should update vault after swap", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1080"), toFixedPtAmt("800")], @@ -239,7 +241,7 @@ describe("RolloverVault", function () { await vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("730"), toFixedPtAmt("1200")], @@ -253,7 +255,7 @@ describe("RolloverVault", function () { }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("100")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); @@ -262,7 +264,7 @@ describe("RolloverVault", function () { }); it("should update vault after swap", async function () { - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1320"), toFixedPtAmt("800")], @@ -270,7 +272,7 @@ describe("RolloverVault", function () { await vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("870"), toFixedPtAmt("1200")], @@ -281,14 +283,13 @@ describe("RolloverVault", function () { describe("when fee is not zero", function () { beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computeUnderlyingToPerpSwapAmt(toFixedPtAmt("100")); - expect(s[0]).to.eq(toFixedPtAmt("85")); - expect(s[1]).to.eq(toFixedPtAmt("5")); + const s = await vault.computeUnderlyingToPerpSwapAmt.staticCall(toFixedPtAmt("100")); + expect(s[0]).to.eq(toFixedPtAmt("90")); + expect(s[1]).to.eq(toFixedPtAmt("0")); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); expect(s[2].vaultTVL).to.eq(toFixedPtAmt("2000")); expect(s[2].seniorTR).to.eq("200"); @@ -303,8 +304,7 @@ describe("RolloverVault", function () { describe("when absolute liquidity is too low", function () { beforeEach(async function () { - await vault.updateReservedUnderlyingBal(toFixedPtAmt("1000")); - await vault.updateReservedSubscriptionPerc(0); + await vault.updateLiquidityLimits(toFixedPtAmt("2500"), toFixedPtAmt("1000"), toPercFixedPtAmt("0")); }); it("should be reverted", async function () { await expect(vault.swapUnderlyingForPerps(toFixedPtAmt("50"))).to.be.revertedWithCustomError( @@ -317,8 +317,7 @@ describe("RolloverVault", function () { describe("when percentage of liquidity is too low", function () { beforeEach(async function () { - await vault.updateReservedUnderlyingBal(0); - await vault.updateReservedSubscriptionPerc(toPercFixedPtAmt("0.25")); + await vault.updateLiquidityLimits(toFixedPtAmt("2500"), toFixedPtAmt("0"), toPercFixedPtAmt("0.25")); }); it("should be reverted", async function () { await expect(vault.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.be.revertedWithCustomError( @@ -331,8 +330,7 @@ describe("RolloverVault", function () { describe("when fee is 100%", function () { it("should be reverted", async function () { - await feePolicy.computePerpMintFeePerc.returns(0); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("1")]); await expect(vault.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.be.revertedWithCustomError( vault, "UnacceptableSwap", @@ -342,8 +340,7 @@ describe("RolloverVault", function () { describe("when fee is greater than 100%", function () { it("should be reverted", async function () { - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("1.01")]); await expect(vault.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.be.reverted; }); }); @@ -351,22 +348,18 @@ describe("RolloverVault", function () { describe("on successful swap with zero fees", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(0); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(0); txFn = () => vault.swapUnderlyingForPerps(toFixedPtAmt("100")); }); it("should mint perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(constants.AddressZero, vault.address, toFixedPtAmt("100")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(ethers.ZeroAddress, vault.target, toFixedPtAmt("100")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("900")); - expect(await perp.balanceOf(vault.address)).to.eq(0); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the perp amt", async function () { - expect(await vault.callStatic.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("100")); + expect(await vault.swapUnderlyingForPerps.staticCall(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("100")); }); it("should transfer underlying from the user", async function () { @@ -378,13 +371,13 @@ describe("RolloverVault", function () { }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -392,13 +385,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("300")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("800"), toFixedPtAmt("1200")], @@ -406,31 +399,28 @@ describe("RolloverVault", function () { }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); }); }); - describe("on successful swap with zero perp fees", function () { + describe("on successful swap with flash fees", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(0); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); txFn = () => vault.swapUnderlyingForPerps(toFixedPtAmt("100")); }); it("should mint perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(constants.AddressZero, vault.address, toFixedPtAmt("90")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(ethers.ZeroAddress, vault.target, toFixedPtAmt("90")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("890")); - expect(await perp.balanceOf(vault.address)).to.eq(0); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the perp amt", async function () { - expect(await vault.callStatic.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("90")); + expect(await vault.swapUnderlyingForPerps.staticCall(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("90")); }); it("should transfer underlying from the user", async function () { @@ -442,83 +432,13 @@ describe("RolloverVault", function () { }); it("should update the vault assets", async function () { - await checkReserveComposition( - perp, - [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], - ); - - await checkVaultAssetComposition( - vault, - [collateralToken, currentTranchesIn[1]], - [toFixedPtAmt("1200"), toFixedPtAmt("800")], - ); - - await txFn(); - - await checkReserveComposition( - perp, - [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("290")], - ); - - await checkVaultAssetComposition( - vault, - [collateralToken, currentTranchesIn[1]], - [toFixedPtAmt("850"), toFixedPtAmt("1160")], - ); - }); - - it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); - await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2010")); - }); - }); - - describe("on successful swap", function () { - let txFn: Promise; - beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); - txFn = () => vault.swapUnderlyingForPerps(toFixedPtAmt("100")); - }); - - it("should mint perps for swap and leave none left over", async function () { - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(constants.AddressZero, vault.address, toFixedPtAmt("90")); - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("885")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("5")); - }); - - it("should return the perp amt", async function () { - expect(await vault.callStatic.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("85")); - }); - - it("should transfer underlying from the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("-100")]); - }); - - it("should transfer back perps to the user", async function () { - await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("85")]); - }); - - it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -526,13 +446,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("290")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("850"), toFixedPtAmt("1160")], @@ -540,17 +460,16 @@ describe("RolloverVault", function () { }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2010")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010")); }); }); describe("on successful swap with imperfect rounding", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); txFn = () => vault.swapUnderlyingForPerps(toFixedPtAmt("100.999999999999999999")); }); @@ -558,20 +477,14 @@ describe("RolloverVault", function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); await expect(txFn()) .to.emit(perp, "Transfer") - .withArgs(constants.AddressZero, vault.address, toFixedPtAmt("90.899999999999999999")); - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("880.799999999999999999")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("10.1")); + .withArgs(ethers.ZeroAddress, vault.target, toFixedPtAmt("90.899999999999999999")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("890.899999999999999999")); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the perp amt", async function () { - expect(await vault.callStatic.swapUnderlyingForPerps(toFixedPtAmt("100.999999999999999999"))).to.eq( - toFixedPtAmt("80.799999999999999999"), + expect(await vault.swapUnderlyingForPerps.staticCall(toFixedPtAmt("100.999999999999999999"))).to.eq( + toFixedPtAmt("90.899999999999999999"), ); }); @@ -584,17 +497,17 @@ describe("RolloverVault", function () { }); it("should transfer back perps to the user", async function () { - await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("80.799999999999999999")]); + await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("90.899999999999999999")]); }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -602,13 +515,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("290.899999999999999999")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("846.500000000000000004"), toFixedPtAmt("1163.599999999999999996")], @@ -616,9 +529,9 @@ describe("RolloverVault", function () { }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2010.10")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010.10")); }); }); @@ -626,28 +539,19 @@ describe("RolloverVault", function () { let txFn: Promise; beforeEach(async function () { await advancePerpQueueToBondMaturity(perp, await getDepositBond(perp)); - await feePolicy.computePerpMintFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computeUnderlyingToPerpVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); txFn = () => vault.swapUnderlyingForPerps(toFixedPtAmt("100")); }); it("should mint perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(constants.AddressZero, vault.address, toFixedPtAmt("90")); - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("885")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("5")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(ethers.ZeroAddress, vault.target, toFixedPtAmt("90")); + expect(await perp.totalSupply()).to.eq(toFixedPtAmt("890")); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the perp amt", async function () { - expect(await vault.callStatic.swapUnderlyingForPerps(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("85")); + expect(await vault.swapUnderlyingForPerps.staticCall(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("90")); }); it("should transfer underlying from the user", async function () { @@ -655,15 +559,15 @@ describe("RolloverVault", function () { }); it("should transfer back perps to the user", async function () { - await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("85")]); + await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("90")]); }); it("should update the vault assets", async function () { - const depositBond = await bondAt(perp.callStatic.getDepositBond()); + const depositBond = await bondAt(await perp.getDepositBond.staticCall()); const depositTranches = await getTranches(depositBond); - await checkReserveComposition(perp, [collateralToken], [toFixedPtAmt("800")]); + await checkPerpComposition(perp, [collateralToken], [toFixedPtAmt("800")]); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -671,13 +575,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, depositTranches[0]], [toFixedPtAmt("800"), toFixedPtAmt("90")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1], depositTranches[1]], [toFixedPtAmt("850"), toFixedPtAmt("800"), toFixedPtAmt("360")], @@ -685,9 +589,9 @@ describe("RolloverVault", function () { }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2010")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010")); }); }); }); @@ -695,13 +599,12 @@ describe("RolloverVault", function () { describe("#swapPerpsForUnderlying", function () { describe("when fee is zero", function () { beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(0); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(0); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [0]); }); describe("when perp price is 1", function () { it("should compute swap amount", async function () { - const s = await vault.callStatic.computePerpToUnderlyingSwapAmt(toFixedPtAmt("100")); + const s = await vault.computePerpToUnderlyingSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("100")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); @@ -712,10 +615,10 @@ describe("RolloverVault", function () { describe("when perp price > 1", function () { beforeEach(async function () { - await collateralToken.transfer(perp.address, toFixedPtAmt("800")); + await collateralToken.transfer(perp.target, toFixedPtAmt("800")); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computePerpToUnderlyingSwapAmt(toFixedPtAmt("100")); + const s = await vault.computePerpToUnderlyingSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("200")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("1600")); @@ -729,7 +632,7 @@ describe("RolloverVault", function () { await rebase(collateralToken, rebaseOracle, -0.9); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computePerpToUnderlyingSwapAmt(toFixedPtAmt("100")); + const s = await vault.computePerpToUnderlyingSwapAmt.staticCall(toFixedPtAmt("100")); expect(s[0]).to.eq(toFixedPtAmt("50")); expect(s[1]).to.eq(0); expect(s[2].perpTVL).to.eq(toFixedPtAmt("400")); @@ -741,14 +644,13 @@ describe("RolloverVault", function () { describe("when fee is not zero", function () { beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.15")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.15")]); }); it("should compute swap amount", async function () { - const s = await vault.callStatic.computePerpToUnderlyingSwapAmt(toFixedPtAmt("100")); - expect(s[0]).to.eq(toFixedPtAmt("80")); - expect(s[1]).to.eq(toFixedPtAmt("5")); + const s = await vault.computePerpToUnderlyingSwapAmt.staticCall(toFixedPtAmt("100")); + expect(s[0]).to.eq(toFixedPtAmt("85")); + expect(s[1]).to.eq(toFixedPtAmt("0")); expect(s[2].perpTVL).to.eq(toFixedPtAmt("800")); expect(s[2].vaultTVL).to.eq(toFixedPtAmt("2000")); expect(s[2].seniorTR).to.eq("200"); @@ -763,8 +665,7 @@ describe("RolloverVault", function () { describe("when fee is 100%", function () { it("should be reverted", async function () { - await feePolicy.computePerpBurnFeePerc.returns(0); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("1")]); await expect(vault.swapPerpsForUnderlying(toFixedPtAmt("100"))).to.be.revertedWithCustomError( vault, "UnacceptableSwap", @@ -774,8 +675,7 @@ describe("RolloverVault", function () { describe("when fee is greater than 100%", function () { it("should be reverted", async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.05")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("1")]); await expect(vault.swapPerpsForUnderlying(toFixedPtAmt("100"))).to.be.reverted; }); }); @@ -783,22 +683,18 @@ describe("RolloverVault", function () { describe("on successful swap with zero fees", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(0); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(0); txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("100")); }); it("should redeem perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("100")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(vault.target, ethers.ZeroAddress, toFixedPtAmt("100")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("700")); - expect(await perp.balanceOf(vault.address)).to.eq(0); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("100")); + expect(await vault.swapPerpsForUnderlying.staticCall(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("100")); }); it("should transfer perps from the user", async function () { @@ -810,13 +706,13 @@ describe("RolloverVault", function () { }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -824,13 +720,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("175"), toFixedPtAmt("175"), toFixedPtAmt("175"), toFixedPtAmt("175")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3)], [toFixedPtAmt("1225"), toFixedPtAmt("700"), toFixedPtAmt("25"), toFixedPtAmt("25"), toFixedPtAmt("25")], @@ -838,31 +734,28 @@ describe("RolloverVault", function () { }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); }); }); - describe("on successful swap with zero perp fees", function () { + describe("on successful swap with flash fees", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(0); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.15")]); txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("100")); }); it("should redeem perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("100")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(vault.target, ethers.ZeroAddress, toFixedPtAmt("100")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("700")); - expect(await perp.balanceOf(vault.address)).to.eq(0); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("90")); + expect(await vault.swapPerpsForUnderlying.staticCall(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("85")); }); it("should transfer perps from the user", async function () { @@ -870,17 +763,17 @@ describe("RolloverVault", function () { }); it("should transfer back underlying to the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("90")]); + await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("85")]); }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -888,114 +781,30 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("175"), toFixedPtAmt("175"), toFixedPtAmt("175"), toFixedPtAmt("175")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3)], - [toFixedPtAmt("1235"), toFixedPtAmt("700"), toFixedPtAmt("25"), toFixedPtAmt("25"), toFixedPtAmt("25")], + [toFixedPtAmt("1240"), toFixedPtAmt("700"), toFixedPtAmt("25"), toFixedPtAmt("25"), toFixedPtAmt("25")], ); }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2010")); - }); - }); - - describe("on successful swap", function () { - let txFn: Promise; - beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.15")); - txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("100")); - }); - - it("should redeem perps for swap and leave none left over", async function () { - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("90")); - expect(await perp.totalSupply()).to.eq(toFixedPtAmt("700")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("10")); - }); - - it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("100"))).to.eq(toFixedPtAmt("75")); - }); - - it("should transfer perps from the user", async function () { - await expect(txFn).to.changeTokenBalances(perp, [deployer], [toFixedPtAmt("-100")]); - }); - - it("should transfer back underlying to the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("75")]); - }); - - it("should update the vault assets", async function () { - await checkReserveComposition( - perp, - [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], - ); - - await checkVaultAssetComposition( - vault, - [collateralToken, currentTranchesIn[1]], - [toFixedPtAmt("1200"), toFixedPtAmt("800")], - ); - - await txFn(); - - await checkReserveComposition( - perp, - [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [ - 0, - toFixedPtAmt("177.215189873417721519"), - toFixedPtAmt("177.215189873417721519"), - toFixedPtAmt("177.215189873417721519"), - toFixedPtAmt("177.215189873417721519"), - ], - ); - - await checkVaultAssetComposition( - vault, - [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3), currentTranchesIn[0]], - [ - toFixedPtAmt("1238.924050632911392"), - toFixedPtAmt("708.8607594936708864"), - toFixedPtAmt("22.784810126582278481"), - toFixedPtAmt("22.784810126582278481"), - toFixedPtAmt("22.784810126582278481"), - toFixedPtAmt("0.000000000000000081"), - ], - ); - }); - - it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); - await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2016.139240506329113843")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2015")); }); }); describe("on successful swap with imperfect rounding", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.1")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.1")]); txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("100.999999999999999999")); }); @@ -1003,20 +812,14 @@ describe("RolloverVault", function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); await expect(txFn()) .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("90.899999999999999999")); + .withArgs(vault.target, ethers.ZeroAddress, toFixedPtAmt("100.999999999999999999")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("699.000000000000000001")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("10.1")); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("100.999999999999999999"))).to.eq( - toFixedPtAmt("80.799999999999999999"), + expect(await vault.swapPerpsForUnderlying.staticCall(toFixedPtAmt("100.999999999999999999"))).to.eq( + toFixedPtAmt("90.899999999999999999"), ); }); @@ -1025,17 +828,17 @@ describe("RolloverVault", function () { }); it("should transfer back underlying to the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("80.799999999999999999")]); + await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("90.899999999999999999")]); }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -1043,67 +846,58 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [ 0, - toFixedPtAmt("176.984428408659323966"), - toFixedPtAmt("176.984428408659323966"), - toFixedPtAmt("176.984428408659323966"), - toFixedPtAmt("176.984428408659323966"), + toFixedPtAmt("174.750000000000000001"), + toFixedPtAmt("174.750000000000000001"), + toFixedPtAmt("174.750000000000000001"), + toFixedPtAmt("174.750000000000000001"), ], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3), currentTranchesIn[0]], [ - toFixedPtAmt("1234.277857956703380001"), - toFixedPtAmt("707.937713634637296000"), - toFixedPtAmt("23.015571591340676034"), - toFixedPtAmt("23.015571591340676034"), - toFixedPtAmt("23.015571591340676034"), - toFixedPtAmt("0.000000000000000034"), + toFixedPtAmt("1235.349999999999999001"), + toFixedPtAmt("699.000000000000000800"), + toFixedPtAmt("25.249999999999999999"), + toFixedPtAmt("25.249999999999999999"), + toFixedPtAmt("25.249999999999999999"), + toFixedPtAmt("0.000000000000000199"), ], ); }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2011.262286365362704103")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2010.099999999999999798")); }); }); describe("on successful swap with some the juniors in the vault", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.15")); - remainingJuniorTranches[1].transfer(vault.address, toFixedPtAmt("100")); - remainingJuniorTranches[2].transfer(vault.address, toFixedPtAmt("100")); - remainingJuniorTranches[3].transfer(vault.address, toFixedPtAmt("100")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.15")]); + remainingJuniorTranches[1].transfer(vault.target, toFixedPtAmt("100")); + remainingJuniorTranches[2].transfer(vault.target, toFixedPtAmt("100")); + remainingJuniorTranches[3].transfer(vault.target, toFixedPtAmt("100")); txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("200")); }); it("should redeem perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("180")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(vault.target, ethers.ZeroAddress, toFixedPtAmt("200")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("600")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("20")); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("200"))).to.eq(toFixedPtAmt("150")); + expect(await vault.swapPerpsForUnderlying.staticCall(toFixedPtAmt("200"))).to.eq(toFixedPtAmt("170")); }); it("should transfer perps from the user", async function () { @@ -1111,17 +905,17 @@ describe("RolloverVault", function () { }); it("should transfer back underlying to the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("150")]); + await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("170")]); }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -1129,69 +923,47 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [ - 0, - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - ], + [0, toFixedPtAmt("150"), toFixedPtAmt("150"), toFixedPtAmt("150"), toFixedPtAmt("150")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, - [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3), currentTranchesIn[0]], - [ - toFixedPtAmt("1655.769230769230769000"), - toFixedPtAmt("615.384615384615384800"), - toFixedPtAmt("21.153846153846153846"), - toFixedPtAmt("21.153846153846153846"), - toFixedPtAmt("21.153846153846153846"), - toFixedPtAmt("0.000000000000000046"), - ], + [collateralToken, currentTranchesIn[1], ...reserveTranches.slice(-3)], + [toFixedPtAmt("1655"), toFixedPtAmt("600"), toFixedPtAmt("25"), toFixedPtAmt("25"), toFixedPtAmt("25")], ); }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2334.615384615384615338")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2330")); }); }); describe("on successful swap with all the juniors in the vault", function () { let txFn: Promise; beforeEach(async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.15")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.15")]); - remainingJuniorTranches[1].transfer(vault.address, toFixedPtAmt("800")); - remainingJuniorTranches[2].transfer(vault.address, toFixedPtAmt("800")); - remainingJuniorTranches[3].transfer(vault.address, toFixedPtAmt("800")); + remainingJuniorTranches[1].transfer(vault.target, toFixedPtAmt("800")); + remainingJuniorTranches[2].transfer(vault.target, toFixedPtAmt("800")); + remainingJuniorTranches[3].transfer(vault.target, toFixedPtAmt("800")); txFn = () => vault.swapPerpsForUnderlying(toFixedPtAmt("200")); }); it("should redeem perps for swap and leave none left over", async function () { expect(await perp.totalSupply()).to.eq(toFixedPtAmt("800")); - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("180")); + await expect(txFn()).to.emit(perp, "Transfer").withArgs(vault.target, ethers.ZeroAddress, toFixedPtAmt("200")); expect(await perp.totalSupply()).to.eq(toFixedPtAmt("600")); - expect(await perp.balanceOf(vault.address)).to.eq(0); - }); - - it("should burn perps as fee", async function () { - await expect(txFn()) - .to.emit(perp, "Transfer") - .withArgs(vault.address, constants.AddressZero, toFixedPtAmt("20")); + expect(await perp.balanceOf(vault.target)).to.eq(0); }); it("should return the underlying amt", async function () { - expect(await vault.callStatic.swapPerpsForUnderlying(toFixedPtAmt("200"))).to.eq(toFixedPtAmt("150")); + expect(await vault.swapPerpsForUnderlying.staticCall(toFixedPtAmt("200"))).to.eq(toFixedPtAmt("170")); }); it("should transfer perps from the user", async function () { @@ -1199,17 +971,17 @@ describe("RolloverVault", function () { }); it("should transfer back underlying to the user", async function () { - await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("150")]); + await expect(txFn).to.changeTokenBalances(collateralToken, [deployer], [toFixedPtAmt("170")]); }); it("should update the vault assets", async function () { - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], [0, toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200"), toFixedPtAmt("200")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [collateralToken, currentTranchesIn[1]], [toFixedPtAmt("1200"), toFixedPtAmt("800")], @@ -1217,19 +989,13 @@ describe("RolloverVault", function () { await txFn(); - await checkReserveComposition( + await checkPerpComposition( perp, [collateralToken, ...reserveTranches.slice(-3), currentTranchesIn[0]], - [ - 0, - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - toFixedPtAmt("153.846153846153846154"), - ], + [0, toFixedPtAmt("150"), toFixedPtAmt("150"), toFixedPtAmt("150"), toFixedPtAmt("150")], ); - await checkVaultAssetComposition( + await checkVaultComposition( vault, [ collateralToken, @@ -1237,41 +1003,29 @@ describe("RolloverVault", function () { remainingJuniorTranches[1], remainingJuniorTranches[2], remainingJuniorTranches[3], - ...reserveTranches.slice(-3), - currentTranchesIn[0], - ], - [ - toFixedPtAmt("1973.076923076923076"), - toFixedPtAmt("615.3846153846153848"), - toFixedPtAmt("615.3846153846153848"), - toFixedPtAmt("615.3846153846153848"), - toFixedPtAmt("615.3846153846153848"), - toFixedPtAmt("0.000000000000000046"), - toFixedPtAmt("0.000000000000000046"), - toFixedPtAmt("0.000000000000000046"), - toFixedPtAmt("0.000000000000000046"), ], + [toFixedPtAmt("2030"), toFixedPtAmt("600"), toFixedPtAmt("600"), toFixedPtAmt("600"), toFixedPtAmt("600")], ); }); it("should update the vault tvl", async function () { - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("2000")); // + 2400 transferred in + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("2000")); await txFn(); - expect(await vault.callStatic.getTVL()).to.eq(toFixedPtAmt("4434.6153846153846152")); + expect(await vault.getTVL.staticCall()).to.eq(toFixedPtAmt("4430")); }); }); describe("when vault reduces underlying liquidity", function () { it("should be reverted", async function () { - await feePolicy.computePerpBurnFeePerc.returns(toPercFixedPtAmt("0.1")); - await feePolicy.computePerpToUnderlyingVaultSwapFeePerc.returns(toPercFixedPtAmt("0.15")); - await vault.swapPerpsForUnderlying(toFixedPtAmt("800")); + await feePolicy.mockMethod("computeFeePerc(uint256,uint256)", [toPercFixedPtAmt("0.15")]); const bond = await getDepositBond(perp); const tranches = await getTranches(bond); - await depositIntoBond(bond, toFixedPtAmt("1000"), deployer); - await tranches[0].approve(perp.address, toFixedPtAmt("200")); - await perp.deposit(tranches[0].address, toFixedPtAmt("200")); + await depositIntoBond(bond, toFixedPtAmt("1200"), deployer); + + await vault.swapPerpsForUnderlying(toFixedPtAmt("800")); + await tranches[0].approve(perp.target, toFixedPtAmt("200")); + await perp.deposit(tranches[0].target, toFixedPtAmt("200")); await expect(vault.swapPerpsForUnderlying(toFixedPtAmt("1"))).to.be.revertedWithCustomError( vault, "InsufficientLiquidity", diff --git a/spot-staking-subgraph/README.md b/spot-staking-subgraph/README.md index 5a04bb42..6bb96bd6 100644 --- a/spot-staking-subgraph/README.md +++ b/spot-staking-subgraph/README.md @@ -8,8 +8,6 @@ yarn codegen yarn build -yarn graph deploy spot-staking \ - --node https://subgraphs.alchemy.com/api/subgraphs/deploy \ - --deploy-key $GRAPH_AUTH \ - --ipfs https://ipfs.satsuma.xyz +export GRAPH_AUTH="SET_KEY" +yarn deploy ``` \ No newline at end of file diff --git a/spot-staking-subgraph/abis/BillBroker.json b/spot-staking-subgraph/abis/BillBroker.json new file mode 100644 index 00000000..ab4ff3a8 --- /dev/null +++ b/spot-staking-subgraph/abis/BillBroker.json @@ -0,0 +1,1691 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidARBound", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPerc", + "type": "error" + }, + { + "inputs": [], + "name": "SlippageTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "UnacceptableSwap", + "type": "error" + }, + { + "inputs": [], + "name": "UnauthorizedCall", + "type": "error" + }, + { + "inputs": [], + "name": "UnexpectedARDelta", + "type": "error" + }, + { + "inputs": [], + "name": "UnexpectedDecimals", + "type": "error" + }, + { + "inputs": [], + "name": "UnreliablePrice", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct ReserveState", + "name": "preOpState", + "type": "tuple" + } + ], + "name": "DepositPerp", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct ReserveState", + "name": "preOpState", + "type": "tuple" + } + ], + "name": "DepositUSD", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct ReserveState", + "name": "preOpState", + "type": "tuple" + } + ], + "name": "SwapPerpsForUSD", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct ReserveState", + "name": "preOpState", + "type": "tuple" + } + ], + "name": "SwapUSDForPerps", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMALS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "arHardBound", + "outputs": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "arSoftBound", + "outputs": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "name": "assetRatio", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtMax", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtMax", + "type": "uint256" + } + ], + "name": "computeMintAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isFirstMint", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + } + ], + "name": "computeMintAmtWithPerp", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "name": "computeMintAmtWithPerp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + } + ], + "name": "computeMintAmtWithUSD", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "name": "computeMintAmtWithUSD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + } + ], + "name": "computePerpToUSDSwapAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "usdAmtOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "name": "computePerpToUSDSwapAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "usdAmtOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lpFeeUsdAmt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "protocolFeeUsdAmt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "arPre", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "arPost", + "type": "uint256" + } + ], + "name": "computePerpToUSDSwapFeePerc", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "burnAmt", + "type": "uint256" + } + ], + "name": "computeRedemptionAmts", + "outputs": [ + { + "internalType": "uint256", + "name": "usdAmtOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtOut", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "name": "computeUSDToPerpSwapAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "perpAmtOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lpFeePerpAmt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "protocolFeePerpAmt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + } + ], + "name": "computeUSDToPerpSwapAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "perpAmtOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "arPre", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "arPost", + "type": "uint256" + } + ], + "name": "computeUSDToPerpSwapFeePerc", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtMax", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtMax", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdAmtMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtMin", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postOpAssetRatioMin", + "type": "uint256" + } + ], + "name": "depositPerp", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "postOpAssetRatioMax", + "type": "uint256" + } + ], + "name": "depositUSD", + "outputs": [ + { + "internalType": "uint256", + "name": "mintAmt", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fees", + "outputs": [ + { + "internalType": "uint256", + "name": "mintFeePerc", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "burnFeePerc", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "perpToUSDSwapFeePercs", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "usdToPerpSwapFeePercs", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "protocolSwapSharePerc", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20Upgradeable", + "name": "usd_", + "type": "address" + }, + { + "internalType": "contract IPerpetualTranche", + "name": "perp_", + "type": "address" + }, + { + "internalType": "contract ISpotPricingStrategy", + "name": "pricingStrategy_", + "type": "address" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "keeper", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "perp", + "outputs": [ + { + "internalType": "contract IPerpetualTranche", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "perpBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "perpPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "perpUnitAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pricingStrategy", + "outputs": [ + { + "internalType": "contract ISpotPricingStrategy", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolFeeCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "burnAmt", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "internalType": "uint256", + "name": "usdAmtOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reserveState", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "usdBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpPrice", + "type": "uint256" + } + ], + "internalType": "struct ReserveState", + "name": "s", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "perpAmtIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usdAmtMin", + "type": "uint256" + } + ], + "name": "swapPerpsForUSD", + "outputs": [ + { + "internalType": "uint256", + "name": "usdAmtOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "usdAmtIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "perpAmtMin", + "type": "uint256" + } + ], + "name": "swapUSDForPerps", + "outputs": [ + { + "internalType": "uint256", + "name": "perpAmtOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "arSoftBound_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "arHardBound_", + "type": "tuple" + } + ], + "name": "updateARBounds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "mintFeePerc", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "burnFeePerc", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "perpToUSDSwapFeePercs", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "lower", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "upper", + "type": "uint256" + } + ], + "internalType": "struct Range", + "name": "usdToPerpSwapFeePercs", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "protocolSwapSharePerc", + "type": "uint256" + } + ], + "internalType": "struct BillBrokerFees", + "name": "fees_", + "type": "tuple" + } + ], + "name": "updateFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "keeper_", + "type": "address" + } + ], + "name": "updateKeeper", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ISpotPricingStrategy", + "name": "pricingStrategy_", + "type": "address" + } + ], + "name": "updatePricingStrategy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "usd", + "outputs": [ + { + "internalType": "contract IERC20Upgradeable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "usdUnitAmt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/spot-staking-subgraph/abis/Wrapper.json b/spot-staking-subgraph/abis/Wrapper.json new file mode 100644 index 00000000..7e04cd87 --- /dev/null +++ b/spot-staking-subgraph/abis/Wrapper.json @@ -0,0 +1,28 @@ +[ + { + "inputs": [], + "name": "underlying", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collateral", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/spot-staking-subgraph/package.json b/spot-staking-subgraph/package.json index 8af2db64..27c82288 100644 --- a/spot-staking-subgraph/package.json +++ b/spot-staking-subgraph/package.json @@ -7,6 +7,7 @@ "codegen": "graph codegen --output-dir ./generated", "build": "graph build", "lint": "yarn prettier --config .prettierrc --write '**/*.ts'", + "deploy": "yarn codegen && yarn build && yarn graph deploy spot-staking --node https://subgraphs.alchemy.com/api/subgraphs/deploy --deploy-key $GRAPH_AUTH", "create-local": "graph create --node http://localhost:8020/ ampleforth/spot-staking", "remove-local": "graph remove --node http://localhost:8020/ ampleforth/spot-staking", "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 ampleforth/spot-staking", diff --git a/spot-staking-subgraph/schema.graphql b/spot-staking-subgraph/schema.graphql index 82f2139a..61e1d6f3 100644 --- a/spot-staking-subgraph/schema.graphql +++ b/spot-staking-subgraph/schema.graphql @@ -1,3 +1,59 @@ +type BillBroker @entity { + " the vault address " + id: ID! + name: String! + symbol: String! + decimals: BigInt! + perp: String! + perpName: String! + perpSymbol: String! + perpDecimals: BigInt! + usd: String! + usdName: String! + usdSymbol: String! + usdDecimals: BigInt! + perpBal: BigDecimal! + usdBal: BigDecimal! + perpPrice: BigDecimal! + usdPrice: BigDecimal! + totalSupply: BigDecimal! + tvl:BigDecimal! + price:BigDecimal! + dailyStats: [BillBrokerDailyStat!]! @derivedFrom(field: "vault") + swapNonce: BigInt! + swaps: [BillBrokerSwap!]! @derivedFrom(field: "vault") +} + +type BillBrokerDailyStat @entity { + "-" + id: ID! + vault: BillBroker! + timestamp: BigInt! + perpBal: BigDecimal! + usdBal: BigDecimal! + perpPrice: BigDecimal! + usdPrice: BigDecimal! + totalSupply: BigDecimal! + usdSwapAmt: BigDecimal! + perpSwapAmt: BigDecimal! + usdFeeAmt: BigDecimal! + perpFeeAmt: BigDecimal! + tvl:BigDecimal! + price:BigDecimal! +} + +type BillBrokerSwap @entity { + "-" + id: ID! + vault: BillBroker! + timestamp: BigInt! + nonce: BigInt! + type: String! + swapAmt: BigDecimal! + feeAmt: BigDecimal! + tx: String! +} + type CharmVault @entity { " the vault address " id: ID! @@ -15,17 +71,11 @@ type CharmVault @entity { token1Decimals: BigInt! token0Bal: BigDecimal! token1Bal: BigDecimal! - token0BalIn: BigDecimal! - token1BalIn: BigDecimal! token0Price: BigDecimal! token1Price: BigDecimal! tvl: BigDecimal! - valueIn: BigDecimal! price: BigDecimal! totalSupply: BigDecimal! - unusedToken0Bal: BigDecimal! - unusedToken1Bal: BigDecimal! - unusedTVL: BigDecimal! dailyStats: [CharmVaultDailyStat!]! @derivedFrom(field: "vault") } @@ -36,12 +86,13 @@ type CharmVaultDailyStat @entity { timestamp: BigInt! token0Bal: BigDecimal! token1Bal: BigDecimal! - token0BalIn: BigDecimal! - token1BalIn: BigDecimal! token0Price: BigDecimal! token1Price: BigDecimal! tvl: BigDecimal! - valueIn: BigDecimal! price: BigDecimal! totalSupply: BigDecimal! -} \ No newline at end of file + token0Fees: BigDecimal! + token1Fees: BigDecimal! + totalFeeVal: BigDecimal! + feeYield: BigDecimal! +} diff --git a/spot-staking-subgraph/src/billBroker.ts b/spot-staking-subgraph/src/billBroker.ts new file mode 100644 index 00000000..c43664be --- /dev/null +++ b/spot-staking-subgraph/src/billBroker.ts @@ -0,0 +1,284 @@ +import { + log, + ethereum, + BigInt, + BigDecimal, + Address, + DataSourceContext, +} from '@graphprotocol/graph-ts' +import { RebasingERC20 } from '../generated/templates' +import { + DepositCall, + RedeemCall, + DepositUSD, + DepositPerp, + SwapPerpsForUSD, + SwapUSDForPerps, +} from '../generated/BillBroker/BillBroker' +import { + BillBroker__computePerpToUSDSwapAmt1InputSStruct, + BillBroker__computeUSDToPerpSwapAmtInputSStruct, +} from '../generated/BillBroker/BillBroker' +import { BillBroker as BillBrokerABI } from '../generated/BillBroker/BillBroker' +import { ERC20 as ERC20ABI } from '../generated/BillBroker/ERC20' +import { BillBroker, BillBrokerDailyStat, BillBrokerSwap } from '../generated/schema' +import { + BIGINT_ZERO, + BIGINT_ONE, + BIGDECIMAL_ZERO, + BIGDECIMAL_ONE, + dayTimestamp, + stringToAddress, + formatBalance, + getUnderlyingAddress, +} from './utils' + +export function fetchBillBroker(address: Address): BillBroker { + let id = address.toHexString() + let vault = BillBroker.load(id) + if (vault === null) { + vault = new BillBroker(id) + let vaultContract = BillBrokerABI.bind(address) + vault.name = vaultContract.name() + vault.symbol = vaultContract.symbol() + vault.decimals = BigInt.fromI32(vaultContract.decimals()) + + let perpAddress = vaultContract.perp() + let perpContract = ERC20ABI.bind(perpAddress) + vault.perp = perpAddress.toHexString() + vault.perpName = perpContract.name() + vault.perpSymbol = perpContract.symbol() + vault.perpDecimals = BigInt.fromI32(perpContract.decimals()) + + let usdAddress = vaultContract.usd() + let usdContract = ERC20ABI.bind(usdAddress) + vault.usd = usdAddress.toHexString() + vault.usdName = usdContract.name() + vault.usdSymbol = usdContract.symbol() + vault.usdDecimals = BigInt.fromI32(usdContract.decimals()) + + vault.perpBal = BIGDECIMAL_ZERO + vault.usdBal = BIGDECIMAL_ZERO + vault.perpPrice = BIGDECIMAL_ZERO + vault.usdPrice = BIGDECIMAL_ZERO + vault.totalSupply = BIGDECIMAL_ZERO + vault.tvl = BIGDECIMAL_ZERO + vault.price = BIGDECIMAL_ZERO + vault.swapNonce = BIGINT_ZERO + + let context = new DataSourceContext() + context.setString('billBroker', id) + RebasingERC20.createWithContext(getUnderlyingAddress(perpAddress), context) + vault.save() + } + return vault as BillBroker +} + +export function fetchBillBrokerDailyStat(vault: BillBroker, timestamp: BigInt): BillBrokerDailyStat { + let id = vault.id.concat('-').concat(timestamp.toString()) + let dailyStat = BillBrokerDailyStat.load(id) + if (dailyStat === null) { + dailyStat = new BillBrokerDailyStat(id) + dailyStat.vault = vault.id + dailyStat.timestamp = timestamp + dailyStat.perpBal = BIGDECIMAL_ZERO + dailyStat.usdBal = BIGDECIMAL_ZERO + dailyStat.perpPrice = BIGDECIMAL_ZERO + dailyStat.usdPrice = BIGDECIMAL_ZERO + dailyStat.totalSupply = BIGDECIMAL_ZERO + dailyStat.usdSwapAmt = BIGDECIMAL_ZERO + dailyStat.perpSwapAmt = BIGDECIMAL_ZERO + dailyStat.usdFeeAmt = BIGDECIMAL_ZERO + dailyStat.perpFeeAmt = BIGDECIMAL_ZERO + dailyStat.tvl = BIGDECIMAL_ZERO + dailyStat.price = BIGDECIMAL_ZERO + dailyStat.save() + } + return dailyStat as BillBrokerDailyStat +} + +function fetchBillBrokerSwap(vault: BillBroker, nonce: BigInt): BillBrokerSwap { + let id = vault.id.concat('-').concat(nonce.toString()) + let swap = BillBrokerSwap.load(id) + if (swap === null) { + swap = new BillBrokerSwap(id) + swap.vault = vault.id + swap.nonce = nonce + swap.type = '' + swap.swapAmt = BIGDECIMAL_ZERO + swap.feeAmt = BIGDECIMAL_ZERO + swap.tx = '0x' + swap.timestamp = BIGINT_ZERO + swap.save() + } + return swap as BillBrokerSwap +} + +export function refreshBillBrokerStats(vault: BillBroker, dailyStat: BillBrokerDailyStat): void { + let vaultContract = BillBrokerABI.bind(stringToAddress(vault.id)) + vault.perpBal = formatBalance(vaultContract.perpBalance(), vault.perpDecimals) + vault.usdBal = formatBalance(vaultContract.usdBalance(), vault.usdDecimals) + vault.totalSupply = formatBalance(vaultContract.totalSupply(), vault.decimals) + vault.save() + + dailyStat.perpBal = vault.perpBal + dailyStat.usdBal = vault.usdBal + dailyStat.totalSupply = vault.totalSupply + dailyStat.save() +} + +export function handleDeposit(call: DepositCall): void { + log.warning('triggered deposit', []) + let vault = fetchBillBroker(call.to) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(call.block.timestamp)) + refreshBillBrokerStats(vault, dailyStat) +} + +export function handleRedeem(call: RedeemCall): void { + log.warning('triggered redeem', []) + let vault = fetchBillBroker(call.to) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(call.block.timestamp)) + refreshBillBrokerStats(vault, dailyStat) +} + +export function handleSwapPerpsForUSD(event: SwapPerpsForUSD): void { + log.warning('triggered swap perps', []) + let vault = fetchBillBroker(event.address) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(event.block.timestamp)) + let swap = fetchBillBrokerSwap(vault, vault.swapNonce.plus(BIGINT_ONE)) + refreshBillBrokerStats(vault, dailyStat) + + vault.perpPrice = formatBalance(event.params.preOpState.perpPrice, vault.decimals) + vault.usdPrice = formatBalance(event.params.preOpState.usdPrice, vault.decimals) + vault.tvl = vault.usdBal.times(vault.usdPrice).plus(vault.perpBal.times(vault.perpPrice)) + vault.price = vault.tvl.div(vault.totalSupply) + vault.save() + + dailyStat.perpPrice = vault.perpPrice + dailyStat.usdPrice = vault.usdPrice + dailyStat.tvl = vault.tvl + dailyStat.price = vault.price + dailyStat.save() + + swap.type = 'perps' + swap.swapAmt = formatBalance(event.params.perpAmtIn, vault.perpDecimals) + swap.tx = event.transaction.hash.toHex() + swap.timestamp = event.block.timestamp + swap.save() + + let vaultContract = BillBrokerABI.bind(stringToAddress(vault.id)) + let reserveStateValues: Array = [ + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.usdBalance), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.perpBalance), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.usdPrice), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.perpPrice), + ] + let reserveStateTuple = changetype(reserveStateValues) + let reserveStateStruct = changetype( + reserveStateTuple, + ) + let r = vaultContract.try_computePerpToUSDSwapAmt1(event.params.perpAmtIn, reserveStateStruct) + if (!r.reverted) { + let swapAmts = r.value + dailyStat.perpSwapAmt = dailyStat.perpSwapAmt.plus( + formatBalance(event.params.perpAmtIn, vault.perpDecimals), + ) + dailyStat.usdFeeAmt = dailyStat.usdFeeAmt.plus( + formatBalance(swapAmts.value1, vault.usdDecimals), + ) + dailyStat.save() + + swap.feeAmt = dailyStat.usdFeeAmt + swap.save() + } +} + +export function handleSwapUSDForPerps(event: SwapUSDForPerps): void { + log.warning('triggered swap usd', []) + let vault = fetchBillBroker(event.address) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(event.block.timestamp)) + let swap = fetchBillBrokerSwap(vault, vault.swapNonce.plus(BIGINT_ONE)) + refreshBillBrokerStats(vault, dailyStat) + + vault.perpPrice = formatBalance(event.params.preOpState.perpPrice, vault.decimals) + vault.usdPrice = formatBalance(event.params.preOpState.usdPrice, vault.decimals) + vault.tvl = vault.usdBal.times(vault.usdPrice).plus(vault.perpBal.times(vault.perpPrice)) + vault.price = vault.tvl.div(vault.totalSupply) + vault.save() + + dailyStat.perpPrice = vault.perpPrice + dailyStat.usdPrice = vault.usdPrice + dailyStat.tvl = vault.tvl + dailyStat.price = vault.price + dailyStat.save() + + swap.type = 'usd' + swap.swapAmt = formatBalance(event.params.usdAmtIn, vault.perpDecimals) + swap.tx = event.transaction.hash.toHex() + swap.timestamp = event.block.timestamp + swap.save() + + let vaultContract = BillBrokerABI.bind(stringToAddress(vault.id)) + let reserveStateValues: Array = [ + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.usdBalance), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.perpBalance), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.usdPrice), + ethereum.Value.fromUnsignedBigInt(event.params.preOpState.perpPrice), + ] + let reserveStateTuple = changetype(reserveStateValues) + let reserveStateStruct = changetype( + reserveStateTuple, + ) + let r = vaultContract.try_computeUSDToPerpSwapAmt(event.params.usdAmtIn, reserveStateStruct) + if (!r.reverted) { + let swapAmts = r.value + dailyStat.usdSwapAmt = dailyStat.usdSwapAmt.plus( + formatBalance(event.params.usdAmtIn, vault.usdDecimals), + ) + dailyStat.perpFeeAmt = dailyStat.perpFeeAmt.plus( + formatBalance(swapAmts.value1, vault.perpDecimals), + ) + dailyStat.save() + + swap.feeAmt = dailyStat.perpFeeAmt + swap.save() + } +} + +export function handleDepositUSD(event: DepositUSD): void { + log.warning('triggered single sided deposit', []) + let vault = fetchBillBroker(event.address) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshBillBrokerStats(vault, dailyStat) + + vault.perpPrice = formatBalance(event.params.preOpState.perpPrice, vault.decimals) + vault.usdPrice = formatBalance(event.params.preOpState.usdPrice, vault.decimals) + vault.tvl = vault.usdBal.times(vault.usdPrice).plus(vault.perpBal.times(vault.perpPrice)) + vault.price = vault.tvl.div(vault.totalSupply) + vault.save() + + dailyStat.perpPrice = vault.perpPrice + dailyStat.usdPrice = vault.usdPrice + dailyStat.tvl = vault.tvl + dailyStat.price = vault.price + dailyStat.save() +} + +export function handleDepositPerp(event: DepositPerp): void { + log.warning('triggered single sided deposit', []) + let vault = fetchBillBroker(event.address) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshBillBrokerStats(vault, dailyStat) + + vault.perpPrice = formatBalance(event.params.preOpState.perpPrice, vault.decimals) + vault.usdPrice = formatBalance(event.params.preOpState.usdPrice, vault.decimals) + vault.tvl = vault.usdBal.times(vault.usdPrice).plus(vault.perpBal.times(vault.perpPrice)) + vault.price = vault.tvl.div(vault.totalSupply) + vault.save() + + dailyStat.perpPrice = vault.perpPrice + dailyStat.usdPrice = vault.usdPrice + dailyStat.tvl = vault.tvl + dailyStat.price = vault.price + dailyStat.save() +} diff --git a/spot-staking-subgraph/src/charmVault.ts b/spot-staking-subgraph/src/charmVault.ts new file mode 100644 index 00000000..3a420458 --- /dev/null +++ b/spot-staking-subgraph/src/charmVault.ts @@ -0,0 +1,153 @@ +import { + log, + ethereum, + BigInt, + BigDecimal, + Address, + DataSourceContext, +} from '@graphprotocol/graph-ts' +import { RebasingERC20 } from '../generated/templates' +import { Deposit, Withdraw, Snapshot, CollectFees } from '../generated/CharmSPOTVault/CharmVault' +import { CharmVault as CharmVaultABI } from '../generated/CharmSPOTVault/CharmVault' +import { UniV3Pool as UniV3PoolABI } from '../generated/CharmSPOTVault/UniV3Pool' +import { ERC20 as ERC20ABI } from '../generated/CharmSPOTVault/ERC20' +import { CharmVault, CharmVaultDailyStat } from '../generated/schema' + +import { + BIGINT_ZERO, + BIGINT_ONE, + BIGDECIMAL_ZERO, + BIGDECIMAL_ONE, + dayTimestamp, + stringToAddress, + formatBalance, + exponentToBigDecimal, + safeDiv, + sqrtPriceX96ToTokenPrices, + getUnderlyingAddress, +} from './utils' + +export function fetchCharmVault(address: Address): CharmVault { + let id = address.toHexString() + let vault = CharmVault.load(id) + if (vault === null) { + vault = new CharmVault(id) + let vaultContract = CharmVaultABI.bind(address) + vault.pool = vaultContract.pool().toHexString() + vault.name = vaultContract.name() + vault.symbol = vaultContract.symbol() + vault.decimals = BigInt.fromI32(vaultContract.decimals()) + + let token0Address = vaultContract.token0() + let token0Contract = ERC20ABI.bind(token0Address) + vault.token0 = token0Address.toHexString() + vault.token0Name = token0Contract.name() + vault.token0Symbol = token0Contract.symbol() + vault.token0Decimals = BigInt.fromI32(token0Contract.decimals()) + + let token1Address = vaultContract.token1() + let token1Contract = ERC20ABI.bind(token1Address) + vault.token1 = token1Address.toHexString() + vault.token1Name = token1Contract.name() + vault.token1Symbol = token1Contract.symbol() + vault.token1Decimals = BigInt.fromI32(token1Contract.decimals()) + + vault.token0Bal = BIGDECIMAL_ZERO + vault.token1Bal = BIGDECIMAL_ZERO + vault.token0Price = BIGDECIMAL_ZERO + vault.token1Price = BIGDECIMAL_ZERO + vault.tvl = BIGDECIMAL_ZERO + vault.price = BIGDECIMAL_ZERO + vault.totalSupply = BIGDECIMAL_ZERO + + let context = new DataSourceContext() + context.setString('charmVault', id) + RebasingERC20.createWithContext(getUnderlyingAddress(token1Address), context) + vault.save() + } + return vault as CharmVault +} + +export function fetchCharmVaultDailyStat(vault: CharmVault, timestamp: BigInt): CharmVaultDailyStat { + let id = vault.id.concat('-').concat(timestamp.toString()) + let dailyStat = CharmVaultDailyStat.load(id) + if (dailyStat === null) { + dailyStat = new CharmVaultDailyStat(id) + dailyStat.vault = vault.id + dailyStat.timestamp = timestamp + dailyStat.token0Bal = BIGDECIMAL_ZERO + dailyStat.token1Bal = BIGDECIMAL_ZERO + dailyStat.token0Price = BIGDECIMAL_ZERO + dailyStat.token1Price = BIGDECIMAL_ZERO + dailyStat.tvl = BIGDECIMAL_ZERO + dailyStat.price = BIGDECIMAL_ZERO + dailyStat.totalSupply = BIGDECIMAL_ZERO + dailyStat.token0Fees = BIGDECIMAL_ZERO + dailyStat.token1Fees = BIGDECIMAL_ZERO + dailyStat.totalFeeVal = BIGDECIMAL_ZERO + dailyStat.feeYield = BIGDECIMAL_ZERO + dailyStat.save() + } + return dailyStat as CharmVaultDailyStat +} + +export function refreshCharmVaultStats(vault: CharmVault, dailyStat: CharmVaultDailyStat): void { + let vaultContract = CharmVaultABI.bind(stringToAddress(vault.id)) + let tokenBals = vaultContract.getTotalAmounts() + let uniPoolContract = UniV3PoolABI.bind(stringToAddress(vault.pool)) + let slot0 = uniPoolContract.slot0() + let sqrtPrice = slot0.value0 + let prices = sqrtPriceX96ToTokenPrices(sqrtPrice, vault.token0Decimals, vault.token1Decimals) + + vault.token0Bal = formatBalance(tokenBals.value0, vault.token0Decimals) + vault.token1Bal = formatBalance(tokenBals.value1, vault.token1Decimals) + vault.token0Price = BIGDECIMAL_ONE + vault.token1Price = prices[0] + vault.tvl = vault.token0Bal.times(vault.token0Price).plus(vault.token1Bal.times(vault.token1Price)) + vault.totalSupply = formatBalance(vaultContract.totalSupply(), vault.decimals) + vault.price = vault.tvl.div(vault.totalSupply) + vault.save() + + dailyStat.token0Bal = vault.token0Bal + dailyStat.token1Bal = vault.token1Bal + dailyStat.token0Price = vault.token0Price + dailyStat.token1Price = vault.token1Price + dailyStat.tvl = vault.tvl + dailyStat.totalSupply = vault.totalSupply + dailyStat.price = vault.price + dailyStat.save() +} + +export function handleDeposit(event: Deposit): void { + log.warning('triggered deposit', []) + let vault = fetchCharmVault(event.address) + let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshCharmVaultStats(vault, dailyStat) +} + +export function handleWithdraw(event: Withdraw): void { + log.warning('triggered withdraw', []) + let vault = fetchCharmVault(event.address) + let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshCharmVaultStats(vault, dailyStat) +} + +export function handleSnapshot(event: Snapshot): void { + log.warning('triggered snapshot', []) + let vault = fetchCharmVault(event.address) + let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshCharmVaultStats(vault, dailyStat) +} + +export function handleFees(event: CollectFees): void { + log.warning('triggered collect fees', []) + let vault = fetchCharmVault(event.address) + let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) + refreshCharmVaultStats(vault, dailyStat) + + dailyStat.token0Fees = dailyStat.token0Fees.plus(formatBalance(event.params.feesToVault0, vault.token0Decimals)) + dailyStat.token1Fees = dailyStat.token1Fees.plus(formatBalance(event.params.feesToVault1, vault.token1Decimals)) + dailyStat.totalFeeVal = dailyStat.token1Fees.times(dailyStat.token1Price).plus(dailyStat.token0Fees.times(dailyStat.token0Price)) + dailyStat.feeYield = dailyStat.totalFeeVal.div(dailyStat.tvl.minus(dailyStat.totalFeeVal)) + dailyStat.save() +} diff --git a/spot-staking-subgraph/src/mappings.ts b/spot-staking-subgraph/src/mappings.ts deleted file mode 100644 index d1430dc8..00000000 --- a/spot-staking-subgraph/src/mappings.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { log, ethereum, BigInt, BigDecimal, Address } from '@graphprotocol/graph-ts' -import { Deposit, Withdraw, Snapshot } from '../generated/CharmVault/CharmVault' -import { CharmVault as CharmVaultABI } from '../generated/CharmVault/CharmVault' -import { UniV3Pool as UniV3PoolABI } from '../generated/CharmVault/UniV3Pool' -import { ERC20 as ERC20ABI } from '../generated/CharmVault/ERC20' -import { CharmVault, CharmVaultDailyStat } from '../generated/schema' - -let BIGINT_ZERO = BigInt.fromI32(0) -let BIGDECIMAL_ZERO = BigDecimal.fromString('0') -let BIGDECIMAL_ONE = BigDecimal.fromString('1') - -let BLOCK_UPDATE_INTERVAL = BigInt.fromI32(240) -let CHARM_VAULT_ID = '0x2dcaff0f75765d7867887fc402b71c841b3a4bfb' -let CHARM_VAULT_UPDATE_BLOCK = BigInt.fromI32(19798270) - -const dayTimestamp = (timestamp: BigInt): BigInt => { - return timestamp.minus(timestamp % BigInt.fromI32(24 * 3600)) -} -const stringToAddress = (id: string): Address => { - return Address.fromString(id) -} -const formatBalance = (wei: BigInt, decimals: BigInt): BigDecimal => { - return wei.toBigDecimal().div( - BigInt.fromI32(10) - .pow(decimals.toI32() as u8) - .toBigDecimal(), - ) -} - -// https://github.com/Uniswap/v3-subgraph/blob/main/src/utils/index.ts#L30 -function exponentToBigDecimal(decimals: BigInt): BigDecimal { - let resultString = '1' - for (let i = 0; i < decimals.toI32(); i++) { - resultString += '0' - } - return BigDecimal.fromString(resultString) -} -function safeDiv(amount0: BigDecimal, amount1: BigDecimal): BigDecimal { - if (amount1.equals(BIGDECIMAL_ZERO)) { - return BIGDECIMAL_ZERO - } else { - return amount0.div(amount1) - } -} -function sqrtPriceX96ToTokenPrices( - sqrtPriceX96: BigInt, - token0Decimals: BigInt, - token1Decimals: BigInt, -): BigDecimal[] { - let Q192 = BigInt.fromI32(2).pow(192 as u8) - let num = sqrtPriceX96.times(sqrtPriceX96).toBigDecimal() - let denom = BigDecimal.fromString(Q192.toString()) - let price1 = num - .div(denom) - .times(exponentToBigDecimal(token0Decimals)) - .div(exponentToBigDecimal(token1Decimals)) - let price0 = safeDiv(BigDecimal.fromString('1'), price1) - return [price0, price1] -} - -function fetchCharmVault(address: Address): CharmVault { - let id = address.toHexString() - let vault = CharmVault.load(id) - if (vault === null) { - vault = new CharmVault(id) - let vaultContract = CharmVaultABI.bind(address) - vault.pool = vaultContract.pool().toHexString() - vault.name = vaultContract.name() - vault.symbol = vaultContract.symbol() - vault.decimals = BigInt.fromI32(vaultContract.decimals()) - - let token0Address = vaultContract.token0() - let token0Contract = ERC20ABI.bind(token0Address) - vault.token0 = token0Address.toHexString() - vault.token0Name = token0Contract.name() - vault.token0Symbol = token0Contract.symbol() - vault.token0Decimals = BigInt.fromI32(token0Contract.decimals()) - - let token1Address = vaultContract.token1() - let token1Contract = ERC20ABI.bind(token1Address) - vault.token1 = token1Address.toHexString() - vault.token1Name = token1Contract.name() - vault.token1Symbol = token1Contract.symbol() - vault.token1Decimals = BigInt.fromI32(token1Contract.decimals()) - - vault.token0Bal = BIGDECIMAL_ZERO - vault.token1Bal = BIGDECIMAL_ZERO - vault.token0BalIn = BIGDECIMAL_ZERO - vault.token1BalIn = BIGDECIMAL_ZERO - vault.token0Price = BIGDECIMAL_ZERO - vault.token1Price = BIGDECIMAL_ZERO - vault.tvl = BIGDECIMAL_ZERO - vault.valueIn = BIGDECIMAL_ZERO - vault.price = BIGDECIMAL_ZERO - vault.totalSupply = BIGDECIMAL_ZERO - vault.unusedToken0Bal = BIGDECIMAL_ZERO - vault.unusedToken1Bal = BIGDECIMAL_ZERO - vault.unusedTVL = BIGDECIMAL_ZERO - vault.save() - } - return vault as CharmVault -} - -function fetchCharmVaultDailyStat(vault: CharmVault, timestamp: BigInt): CharmVaultDailyStat { - let id = vault.id.concat('-').concat(timestamp.toString()) - let dailyStat = CharmVaultDailyStat.load(id) - if (dailyStat === null) { - dailyStat = new CharmVaultDailyStat(id) - dailyStat.vault = vault.id - dailyStat.timestamp = timestamp - dailyStat.token0Bal = BIGDECIMAL_ZERO - dailyStat.token1Bal = BIGDECIMAL_ZERO - dailyStat.token0BalIn = BIGDECIMAL_ZERO - dailyStat.token1BalIn = BIGDECIMAL_ZERO - dailyStat.token0Price = BIGDECIMAL_ZERO - dailyStat.token1Price = BIGDECIMAL_ZERO - dailyStat.tvl = BIGDECIMAL_ZERO - dailyStat.valueIn = BIGDECIMAL_ZERO - dailyStat.price = BIGDECIMAL_ZERO - dailyStat.totalSupply = BIGDECIMAL_ZERO - dailyStat.save() - } - return dailyStat as CharmVaultDailyStat -} - -function refreshCharmVaultStats(vault: CharmVault, dailyStat: CharmVaultDailyStat): void { - let vaultContract = CharmVaultABI.bind(stringToAddress(vault.id)) - let tokenBals = vaultContract.getTotalAmounts() - let uniPoolContract = UniV3PoolABI.bind(stringToAddress(vault.pool)) - let slot0 = uniPoolContract.slot0() - let sqrtPrice = slot0.value0 - let prices = sqrtPriceX96ToTokenPrices(sqrtPrice, vault.token0Decimals, vault.token1Decimals) - - vault.token0Bal = formatBalance(tokenBals.value0, vault.token0Decimals) - vault.token1Bal = formatBalance(tokenBals.value1, vault.token1Decimals) - vault.token0Price = prices[0] - vault.token1Price = prices[1] - vault.tvl = vault.token0Bal.plus(vault.token1Bal.times(vault.token0Price)) - vault.totalSupply = formatBalance(vaultContract.totalSupply(), vault.decimals) - vault.price = vault.tvl.div(vault.totalSupply) - vault.unusedToken0Bal = formatBalance(vaultContract.getBalance0(), vault.token0Decimals) - vault.unusedToken1Bal = formatBalance(vaultContract.getBalance1(), vault.token1Decimals) - vault.unusedTVL = vault.unusedToken0Bal.plus(vault.unusedToken1Bal.times(vault.token0Price)) - vault.save() - - dailyStat.token0Bal = vault.token0Bal - dailyStat.token1Bal = vault.token1Bal - dailyStat.token0Price = vault.token0Price - dailyStat.token1Price = vault.token1Price - dailyStat.tvl = vault.tvl - dailyStat.totalSupply = vault.totalSupply - dailyStat.price = vault.price - dailyStat.save() -} - -export function handleDeposit(event: Deposit): void { - log.debug('triggered deposit', []) - let vault = fetchCharmVault(event.address) - let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) - refreshCharmVaultStats(vault, dailyStat) - vault.token0BalIn = vault.token0BalIn.plus( - formatBalance(event.params.amount0, vault.token0Decimals), - ) - vault.token1BalIn = vault.token1BalIn.plus( - formatBalance(event.params.amount1, vault.token1Decimals), - ) - vault.valueIn = vault.token0BalIn.plus(vault.token1BalIn.times(vault.token0Price)) - vault.save() - - dailyStat.token0BalIn = vault.token0BalIn - dailyStat.token1BalIn = vault.token1BalIn - dailyStat.valueIn = vault.valueIn - dailyStat.save() -} - -export function handleWithdraw(event: Withdraw): void { - log.debug('triggered withdraw', []) - let vault = fetchCharmVault(event.address) - let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) - refreshCharmVaultStats(vault, dailyStat) - vault.token0BalIn = vault.token0BalIn.minus( - formatBalance(event.params.amount0, vault.token0Decimals), - ) - vault.token1BalIn = vault.token1BalIn.minus( - formatBalance(event.params.amount1, vault.token1Decimals), - ) - vault.valueIn = vault.token0BalIn.plus(vault.token1BalIn.times(vault.token0Price)) - vault.save() - - dailyStat.token0BalIn = vault.token0BalIn - dailyStat.token1BalIn = vault.token1BalIn - dailyStat.valueIn = vault.valueIn - dailyStat.save() - dailyStat.save() -} - -export function handleSnapshot(event: Snapshot): void { - log.debug('triggered snapshot', []) - let vault = fetchCharmVault(event.address) - let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(event.block.timestamp)) - refreshCharmVaultStats(vault, dailyStat) -} - -export function refreshStore(block: ethereum.Block): void { - let timeForUpdate = - block.number.gt(CHARM_VAULT_UPDATE_BLOCK) && - block.number.mod(BLOCK_UPDATE_INTERVAL).equals(BIGINT_ZERO) - if (timeForUpdate) { - log.debug('triggered store refresh', []) - let vault = fetchCharmVault(stringToAddress(CHARM_VAULT_ID)) - let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(block.timestamp)) - refreshCharmVaultStats(vault, dailyStat) - } -} diff --git a/spot-staking-subgraph/src/rebasingToken.ts b/spot-staking-subgraph/src/rebasingToken.ts new file mode 100644 index 00000000..0942d556 --- /dev/null +++ b/spot-staking-subgraph/src/rebasingToken.ts @@ -0,0 +1,34 @@ +import { log, dataSource, Address, BigInt } from '@graphprotocol/graph-ts' +import { LogRebase, Rebase } from '../generated/templates/RebasingERC20/RebasingERC20' +import { stringToAddress, dayTimestamp } from './utils' +import { fetchBillBroker, fetchBillBrokerDailyStat, refreshBillBrokerStats } from './billBroker' +import { fetchCharmVault, fetchCharmVaultDailyStat, refreshCharmVaultStats } from './charmVault' + +function _handleRebase(address: Address, timestamp: BigInt): void { + let context = dataSource.context() + if (context.get('billBroker') != null) { + let id = context.getString('billBroker') + log.warning('billBrokerRefresh: {}', [id]) + let vault = fetchBillBroker(stringToAddress(id)) + let dailyStat = fetchBillBrokerDailyStat(vault, dayTimestamp(timestamp)) + refreshBillBrokerStats(vault, dailyStat) + } + + if (context.get('charmVault') != null) { + let id = context.getString('charmVault') + log.warning('charmVaultRefresh: {}', [id]) + let vault = fetchCharmVault(stringToAddress(id)) + let dailyStat = fetchCharmVaultDailyStat(vault, dayTimestamp(timestamp)) + refreshCharmVaultStats(vault, dailyStat) + } +} + +export function handleRebase(event: Rebase): void { + log.warning('triggered handleRebase', []) + _handleRebase(event.address, event.block.timestamp) +} + +export function handleLogRebase(event: LogRebase): void { + log.warning('triggered handleLogRebase', []) + _handleRebase(event.address, event.block.timestamp) +} diff --git a/spot-staking-subgraph/src/utils.ts b/spot-staking-subgraph/src/utils.ts new file mode 100644 index 00000000..a5aa75c4 --- /dev/null +++ b/spot-staking-subgraph/src/utils.ts @@ -0,0 +1,70 @@ +import { BigInt, BigDecimal, Address } from '@graphprotocol/graph-ts' + +import { Wrapper as WrapperABI } from '../generated/CharmSPOTVault/Wrapper' + +export let BIGINT_ZERO = BigInt.fromI32(0) +export let BIGINT_ONE = BigInt.fromI32(1) +export let BIGDECIMAL_ZERO = BigDecimal.fromString('0') +export let BIGDECIMAL_ONE = BigDecimal.fromString('1') + +export const dayTimestamp = (timestamp: BigInt): BigInt => { + return timestamp.minus(timestamp % BigInt.fromI32(24 * 3600)) +} + +export const stringToAddress = (id: string): Address => { + return Address.fromString(id) +} + +export const formatBalance = (wei: BigInt, decimals: BigInt): BigDecimal => { + return wei.toBigDecimal().div( + BigInt.fromI32(10) + .pow(decimals.toI32() as u8) + .toBigDecimal(), + ) +} + +// https://github.com/Uniswap/v3-subgraph/blob/main/src/utils/index.ts#L30 +export function exponentToBigDecimal(decimals: BigInt): BigDecimal { + let resultString = '1' + for (let i = 0; i < decimals.toI32(); i++) { + resultString += '0' + } + return BigDecimal.fromString(resultString) +} + +export function safeDiv(amount0: BigDecimal, amount1: BigDecimal): BigDecimal { + if (amount1.equals(BIGDECIMAL_ZERO)) { + return BIGDECIMAL_ZERO + } else { + return amount0.div(amount1) + } +} + +export function sqrtPriceX96ToTokenPrices( + sqrtPriceX96: BigInt, + token0Decimals: BigInt, + token1Decimals: BigInt, +): BigDecimal[] { + let Q192 = BigInt.fromI32(2).pow(192 as u8) + let num = sqrtPriceX96.times(sqrtPriceX96).toBigDecimal() + let denom = BigDecimal.fromString(Q192.toString()) + let price1 = num + .div(denom) + .times(exponentToBigDecimal(token0Decimals)) + .div(exponentToBigDecimal(token1Decimals)) + let price0 = safeDiv(BigDecimal.fromString('1'), price1) + return [price0, price1] +} + +export function getUnderlyingAddress(tokenAddress: Address): Address { + let wrapperContract = WrapperABI.bind(tokenAddress) + let underlyingResult = wrapperContract.try_underlying() + if (!underlyingResult.reverted) { + return underlyingResult.value + } + let collateralResult = wrapperContract.try_collateral() + if (!collateralResult.reverted) { + return collateralResult.value + } + return Address.fromString('0x0000000000000000000000000000000000000000') +} \ No newline at end of file diff --git a/spot-staking-subgraph/subgraph.yaml b/spot-staking-subgraph/subgraph.yaml index 007875fc..65139dd2 100644 --- a/spot-staking-subgraph/subgraph.yaml +++ b/spot-staking-subgraph/subgraph.yaml @@ -3,9 +3,81 @@ description: Subgraph to keep track of spot staking repository: http://github.com/ampleforth/spot schema: file: ./schema.graphql +templates: + - kind: ethereum/contract + name: RebasingERC20 + network: mainnet + source: + abi: RebasingERC20 + mapping: + kind: ethereum/events + apiVersion: 0.0.4 + language: wasm/assemblyscript + entities: + - Rebase + - LogRebase + abis: + - name: BillBroker + file: ./abis/BillBroker.json + - name: CharmVault + file: ./abis/CharmVault.json + - name: UniV3Pool + file: ./abis/UniV3Pool.json + - name: Wrapper + file: ./abis/Wrapper.json + - name: ERC20 + file: ./abis/ERC20.json + - name: RebasingERC20 + file: ./abis/RebasingERC20.json + eventHandlers: + - event: Rebase(indexed uint256,uint256) + handler: handleRebase + - event: LogRebase(indexed uint256,uint256) + handler: handleLogRebase + file: ./src/rebasingToken.ts + dataSources: - kind: ethereum/contract - name: CharmVault + name: BillBroker + network: mainnet + source: + address: "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" + abi: BillBroker + startBlock: 20127140 + mapping: + kind: ethereum/events + apiVersion: 0.0.4 + language: wasm/assemblyscript + entities: + - BillBroker + - ERC20 + abis: + - name: BillBroker + file: ./abis/BillBroker.json + - name: Wrapper + file: ./abis/Wrapper.json + - name: ERC20 + file: ./abis/ERC20.json + - name: RebasingERC20 + file: ./abis/RebasingERC20.json + eventHandlers: + - event: DepositUSD(uint256,(uint256,uint256,uint256,uint256)) + handler: handleDepositUSD + - event: DepositPerp(uint256,(uint256,uint256,uint256,uint256)) + handler: handleDepositPerp + - event: SwapPerpsForUSD(uint256,(uint256,uint256,uint256,uint256)) + handler: handleSwapPerpsForUSD + - event: SwapUSDForPerps(uint256,(uint256,uint256,uint256,uint256)) + handler: handleSwapUSDForPerps + callHandlers: + - function: deposit(uint256,uint256,uint256,uint256) + handler: handleDeposit + - function: redeem(uint256) + handler: handleRedeem + file: ./src/billBroker.ts + + - kind: ethereum/contract + name: CharmSPOTVault network: mainnet source: address: "0x2dcaff0f75765d7867887fc402b71c841b3a4bfb" @@ -24,8 +96,49 @@ dataSources: file: ./abis/CharmVault.json - name: UniV3Pool file: ./abis/UniV3Pool.json + - name: Wrapper + file: ./abis/Wrapper.json + - name: ERC20 + file: ./abis/ERC20.json + - name: RebasingERC20 + file: ./abis/RebasingERC20.json + eventHandlers: + - event: Deposit(indexed address,indexed address,uint256,uint256,uint256) + handler: handleDeposit + - event: Withdraw(indexed address,indexed address,uint256,uint256,uint256) + handler: handleWithdraw + - event: Snapshot(int24,uint256,uint256,uint256) + handler: handleSnapshot + - event: CollectFees(uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleFees + file: ./src/charmVault.ts + + - kind: ethereum/contract + name: CharmWAMPLVault + network: mainnet + source: + address: "0x9658b5bdcad59dd0b7b936d955e5df81ea2b4dcb" + abi: CharmVault + startBlock: 20162628 + mapping: + kind: ethereum/events + apiVersion: 0.0.4 + language: wasm/assemblyscript + entities: + - CharmVault + - UniV3Pool + - ERC20 + abis: + - name: CharmVault + file: ./abis/CharmVault.json + - name: UniV3Pool + file: ./abis/UniV3Pool.json + - name: Wrapper + file: ./abis/Wrapper.json - name: ERC20 file: ./abis/ERC20.json + - name: RebasingERC20 + file: ./abis/RebasingERC20.json eventHandlers: - event: Deposit(indexed address,indexed address,uint256,uint256,uint256) handler: handleDeposit @@ -33,6 +146,6 @@ dataSources: handler: handleWithdraw - event: Snapshot(int24,uint256,uint256,uint256) handler: handleSnapshot - blockHandlers: - - handler: refreshStore - file: ./src/mappings.ts \ No newline at end of file + - event: CollectFees(uint256,uint256,uint256,uint256,uint256,uint256) + handler: handleFees + file: ./src/charmVault.ts \ No newline at end of file diff --git a/spot-subgraph/schema.graphql b/spot-subgraph/schema.graphql index 624b640d..c37a2229 100644 --- a/spot-subgraph/schema.graphql +++ b/spot-subgraph/schema.graphql @@ -355,4 +355,10 @@ type RolloverVaultDailyStat @entity { " the total value of swaps on the given day " totalSwapValue: BigDecimal! + + " the total value of underlying to perp swaps on the given day " + totalUnderlyingToPerpSwapValue: BigDecimal! + + " the total value of perp to underlying swaps on the given day " + totalPerpToUnderlyingSwapValue: BigDecimal! } \ No newline at end of file diff --git a/spot-subgraph/scripts/deploy.sh b/spot-subgraph/scripts/deploy.sh index a6bcbc3f..e6c0c3c6 100755 --- a/spot-subgraph/scripts/deploy.sh +++ b/spot-subgraph/scripts/deploy.sh @@ -9,5 +9,4 @@ yarn build yarn graph deploy $2 \ --node https://subgraphs.alchemy.com/api/subgraphs/deploy \ - --deploy-key $GRAPH_AUTH \ - --ipfs https://ipfs.satsuma.xyz \ No newline at end of file + --deploy-key $GRAPH_AUTH \ No newline at end of file diff --git a/spot-subgraph/src/data/rolloverVault.ts b/spot-subgraph/src/data/rolloverVault.ts index 77f7919c..47575d5e 100644 --- a/spot-subgraph/src/data/rolloverVault.ts +++ b/spot-subgraph/src/data/rolloverVault.ts @@ -4,7 +4,7 @@ import { RolloverVaultAsset, ScaledUnderlyingVaultDepositorBalance, RolloverVaultDailyStat, - Tranche + Tranche, } from '../../generated/schema' import { RolloverVault as RolloverVaultABI } from '../../generated/RolloverVault/RolloverVault' import { ERC20 as ERC20ABI } from '../../generated/BondFactory/ERC20' @@ -144,10 +144,10 @@ export function refreshRolloverVaultRebaseMultiplier(vault: RolloverVault): void .plus(vaultPerpBalance) .plus(vaultZBalance) .plus(vaultUnderlyingBalance) - if(denominator.gt(BIGDECIMAL_ZERO)){ + if (denominator.gt(BIGDECIMAL_ZERO)) { vault.rebaseMultiplier = numerator.div(denominator) } - vault.save() + vault.save() } export function refreshRolloverVaultDailyStat(dailyStat: RolloverVaultDailyStat): void { @@ -246,6 +246,8 @@ export function fetchRolloverVaultDailyStat( dailyStat.price = BIGDECIMAL_ZERO dailyStat.totalSupply = BIGDECIMAL_ZERO dailyStat.totalSwapValue = BIGDECIMAL_ZERO + dailyStat.totalUnderlyingToPerpSwapValue = BIGDECIMAL_ZERO + dailyStat.totalPerpToUnderlyingSwapValue = BIGDECIMAL_ZERO } return dailyStat as RolloverVaultDailyStat } diff --git a/spot-subgraph/src/mappings/rolloverVault.ts b/spot-subgraph/src/mappings/rolloverVault.ts index d29317c7..0aad7c70 100644 --- a/spot-subgraph/src/mappings/rolloverVault.ts +++ b/spot-subgraph/src/mappings/rolloverVault.ts @@ -135,6 +135,9 @@ export function handleUnderlyingToPerpSwap(call: SwapUnderlyingForPerpsCall): vo let dailyStat = fetchRolloverVaultDailyStat(vault, dayTimestamp(call.block.timestamp)) dailyStat.totalSwapValue = dailyStat.totalSwapValue.plus(underlyingAmtIn) + dailyStat.totalUnderlyingToPerpSwapValue = dailyStat.totalUnderlyingToPerpSwapValue.plus( + underlyingAmtIn, + ) dailyStat.save() } @@ -153,5 +156,8 @@ export function handlePerpToUnderlyingSwap(call: SwapPerpsForUnderlyingCall): vo let dailyStat = fetchRolloverVaultDailyStat(vault, dayTimestamp(call.block.timestamp)) dailyStat.totalSwapValue = dailyStat.totalSwapValue.plus(perpAmtIn.times(perp.price)) + dailyStat.totalPerpToUnderlyingSwapValue = dailyStat.totalPerpToUnderlyingSwapValue.plus( + perpAmtIn.times(perp.price), + ) dailyStat.save() } diff --git a/spot-vaults/.openzeppelin/mainnet.json b/spot-vaults/.openzeppelin/mainnet.json index bcc7efee..befb1c87 100644 --- a/spot-vaults/.openzeppelin/mainnet.json +++ b/spot-vaults/.openzeppelin/mainnet.json @@ -326,6 +326,325 @@ }, "namespaces": {} } + }, + "d00a4d75788e81fee448c9ae6273844f2de0999fa1330a99643609691807db49": { + "address": "0x0CE64cD7583864f7005898Aa133C74DBccaca063", + "txHash": "0x9116fa3d9dd6a540f56cd7e85144a0eaf7408d8fcb32dde8f5993884d5321ac1", + "layout": { + "solcVersion": "0.8.24", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:40" + }, + { + "label": "_balances", + "offset": 0, + "slot": "51", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "52", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "53", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "_name", + "offset": 0, + "slot": "54", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:46" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "55", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:47" + }, + { + "label": "__gap", + "offset": 0, + "slot": "56", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:376" + }, + { + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC20BurnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol:51" + }, + { + "label": "_owner", + "offset": 0, + "slot": "151", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "152", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" + }, + { + "label": "_paused", + "offset": 0, + "slot": "201", + "type": "t_bool", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" + }, + { + "label": "__gap", + "offset": 0, + "slot": "202", + "type": "t_array(t_uint256)49_storage", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" + }, + { + "label": "_status", + "offset": 0, + "slot": "251", + "type": "t_uint256", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" + }, + { + "label": "__gap", + "offset": 0, + "slot": "252", + "type": "t_array(t_uint256)49_storage", + "contract": "ReentrancyGuardUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" + }, + { + "label": "perp", + "offset": 0, + "slot": "301", + "type": "t_contract(IPerpetualTranche)389", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:89" + }, + { + "label": "usd", + "offset": 0, + "slot": "302", + "type": "t_contract(IERC20Upgradeable)1872", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:92" + }, + { + "label": "usdUnitAmt", + "offset": 0, + "slot": "303", + "type": "t_uint256", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:95" + }, + { + "label": "perpUnitAmt", + "offset": 0, + "slot": "304", + "type": "t_uint256", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:98" + }, + { + "label": "keeper", + "offset": 0, + "slot": "305", + "type": "t_address", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:103" + }, + { + "label": "pricingStrategy", + "offset": 0, + "slot": "306", + "type": "t_contract(ISpotPricingStrategy)8533", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:106" + }, + { + "label": "fees", + "offset": 0, + "slot": "307", + "type": "t_struct(BillBrokerFees)8494_storage", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:109" + }, + { + "label": "arHardBound", + "offset": 0, + "slot": "314", + "type": "t_struct(Range)8475_storage", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:112" + }, + { + "label": "arSoftBound", + "offset": 0, + "slot": "316", + "type": "t_struct(Range)8475_storage", + "contract": "BillBroker", + "src": "contracts/BillBroker.sol:116" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IERC20Upgradeable)1872": { + "label": "contract IERC20Upgradeable", + "numberOfBytes": "20" + }, + "t_contract(IPerpetualTranche)389": { + "label": "contract IPerpetualTranche", + "numberOfBytes": "20" + }, + "t_contract(ISpotPricingStrategy)8533": { + "label": "contract ISpotPricingStrategy", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(BillBrokerFees)8494_storage": { + "label": "struct BillBrokerFees", + "members": [ + { + "label": "mintFeePerc", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "burnFeePerc", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "perpToUSDSwapFeePercs", + "type": "t_struct(Range)8475_storage", + "offset": 0, + "slot": "2" + }, + { + "label": "usdToPerpSwapFeePercs", + "type": "t_struct(Range)8475_storage", + "offset": 0, + "slot": "4" + }, + { + "label": "protocolSwapSharePerc", + "type": "t_uint256", + "offset": 0, + "slot": "6" + } + ], + "numberOfBytes": "224" + }, + "t_struct(Range)8475_storage": { + "label": "struct Range", + "members": [ + { + "label": "lower", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "upper", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } } } } diff --git a/spot-vaults/README.md b/spot-vaults/README.md index 16c86577..e915bacc 100644 --- a/spot-vaults/README.md +++ b/spot-vaults/README.md @@ -5,15 +5,14 @@ This repository is a collection of vault strategies leveraging the SPOT system. The official mainnet addresses are: - Bill Broker (SPOT-USDC): [0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB](https://etherscan.io/address/0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB) -- WethWamplManager: [0x6785fa26191eb531c54fd093931f395c4b01b583](https://etherscan.io/address/0x6785fa26191eb531c54fd093931f395c4b01b583) -- UsdcSpotManager: [0x780eB92040bf24cd9BF993505390e88E8ED59935](https://etherscan.io/address/0x780eB92040bf24cd9BF993505390e88E8ED59935) -- SpotAppraiser: [0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c](https://etherscan.io/address/0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c) Used by the Bill Broker -- SpotCDRPricer: [0xa76df05BAb61444fa2C1c5c1e14A3aD912A00EbA](https://etherscan.io/address/0xa76df05BAb61444fa2C1c5c1e14A3aD912A00EbA) Used by the Charm USDC/SPOT auto manager +- WethWamplManager: [0x574fca658b4B59E965C0e5f74761AE0Ac41DA6a7](https://etherscan.io/address/0x574fca658b4B59E965C0e5f74761AE0Ac41DA6a7) +- UsdcSpotManager: [0x2f67158859Fe0f69f5773570eC60444Fe0c1693c](https://etherscan.io/address/0x2f67158859Fe0f69f5773570eC60444Fe0c1693c) +- SpotPricer: [0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881](https://etherscan.io/address/0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881) The official testnet addresses are: - Bill Broker (SPOT-USDC): [0xc3f6D1F1d253EdC8B34D78Bc6cDD2b3eEFAd76BD](https://sepolia.etherscan.io/address/0xc3f6D1F1d253EdC8B34D78Bc6cDD2b3eEFAd76BD) -- SpotAppraiser: [0x08c5b39F000705ebeC8427C1d64D6262392944EE](https://sepolia.etherscan.io/address/0x08c5b39F000705ebeC8427C1d64D6262392944EE) +- SpotAppraiser **(deprecated)**: [0x08c5b39F000705ebeC8427C1d64D6262392944EE](https://sepolia.etherscan.io/address/0x08c5b39F000705ebeC8427C1d64D6262392944EE) ## Install diff --git a/spot-vaults/contracts/BillBroker.sol b/spot-vaults/contracts/BillBroker.sol index 0e12f3b4..9ecfc298 100644 --- a/spot-vaults/contracts/BillBroker.sol +++ b/spot-vaults/contracts/BillBroker.sol @@ -5,17 +5,19 @@ import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/O import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; -import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; -import { SignedMathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; + import { ERC20BurnableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import { IERC20MetadataUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; - +import { LineHelpers } from "./_utils/LineHelpers.sol"; +import { MathHelpers } from "./_utils/MathHelpers.sol"; import { IPerpetualTranche } from "@ampleforthorg/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol"; -import { ISpotPricingStrategy } from "./_interfaces/ISpotPricingStrategy.sol"; -import { ReserveState, BillBrokerFees, Line, Range } from "./_interfaces/BillBrokerTypes.sol"; -import { UnacceptableSwap, UnreliablePrice, UnexpectedDecimals, InvalidPerc, InvalidARBound, SlippageTooHigh, UnauthorizedCall, UnexpectedARDelta } from "./_interfaces/BillBrokerErrors.sol"; +import { IPerpPricer } from "./_interfaces/IPerpPricer.sol"; +import { ReserveState, BillBrokerFees } from "./_interfaces/types/BillBrokerTypes.sol"; +import { Line, Range } from "./_interfaces/types/CommonTypes.sol"; +import { UnacceptableSwap, UnreliablePrice, UnexpectedDecimals, InvalidPerc, SlippageTooHigh, UnauthorizedCall } from "./_interfaces/errors/CommonErrors.sol"; +import { InvalidARBound } from "./_interfaces/errors/BillBrokerErrors.sol"; /** * @title BillBroker @@ -70,17 +72,20 @@ contract BillBroker is // Math using MathUpgradeable for uint256; - using SafeCastUpgradeable for uint256; - using SafeCastUpgradeable for int256; - using SignedMathUpgradeable for int256; + using MathHelpers for uint256; + using MathHelpers for int256; + using LineHelpers for Line; //------------------------------------------------------------------------- // Constants & Immutables uint256 public constant DECIMALS = 18; uint256 public constant ONE = (10 ** DECIMALS); + uint256 public constant TWO = ONE * 2; uint256 private constant INITIAL_RATE = 1000000; uint256 public constant MINIMUM_LIQUIDITY = 10 ** 22; + uint256 public constant MAX_FEE_FACTOR = ((ONE * 6) / 5); // 1.2 or 20% + uint256 public constant MAX_ASSET_RATIO = uint256(type(int256).max); //------------------------------------------------------------------------- // Storage @@ -102,8 +107,8 @@ contract BillBroker is /// @return The address of the keeper. address public keeper; - /// @notice The pricing strategy. - ISpotPricingStrategy public pricingStrategy; + /// @notice The pricing oracle for perp and usd tokens. + IPerpPricer public oracle; /// @notice All of the system fees. BillBrokerFees public fees; @@ -112,30 +117,30 @@ contract BillBroker is Range public arHardBound; /// @notice The asset ratio bounds outside which swapping is still functional but, - /// the swap fees transition from a flat percentage fee to a linear function. + /// the swap fees transition from a constant fee to a linear function. Range public arSoftBound; //-------------------------------------------------------------------------- // Events - /// @notice Emitted when a user deposits USD tokens to mint LP tokens. - /// @param usdAmtIn The amount of USD tokens deposited. - /// @param preOpState The reserve state before the deposit operation. + /// @notice Emitted when a user deposits usd tokens to mint LP tokens. + /// @param usdAmtIn The amount of usd tokens deposited. + /// @param preOpState Pre-operation reserve state. event DepositUSD(uint256 usdAmtIn, ReserveState preOpState); /// @notice Emitted when a user deposits Perp tokens to mint LP tokens. /// @param perpAmtIn The amount of Perp tokens deposited. - /// @param preOpState The reserve state before the deposit operation. + /// @param preOpState Pre-operation reserve state. event DepositPerp(uint256 perpAmtIn, ReserveState preOpState); - /// @notice Emitted when a user swaps Perp tokens for USD tokens. + /// @notice Emitted when a user swaps Perp tokens for usd tokens. /// @param perpAmtIn The amount of Perp tokens swapped in. - /// @param preOpState The reserve state before the swap operation. + /// @param preOpState Pre-operation reserve state. event SwapPerpsForUSD(uint256 perpAmtIn, ReserveState preOpState); - /// @notice Emitted when a user swaps USD tokens for Perp tokens. - /// @param usdAmtIn The amount of USD tokens swapped in. - /// @param preOpState The reserve state before the swap operation. + /// @notice Emitted when a user swaps usd tokens for Perp tokens. + /// @param usdAmtIn The amount of usd tokens swapped in. + /// @param preOpState Pre-operation reserve state. event SwapUSDForPerps(uint256 usdAmtIn, ReserveState preOpState); //-------------------------------------------------------------------------- @@ -161,13 +166,13 @@ contract BillBroker is /// @param symbol ERC-20 Symbol of the Bill broker LP token. /// @param usd_ Address of the usd token. /// @param perp_ Address of the perp token. - /// @param pricingStrategy_ Address of the pricing strategy contract. + /// @param oracle_ Address of the oracle contract. function init( string memory name, string memory symbol, IERC20Upgradeable usd_, IPerpetualTranche perp_, - ISpotPricingStrategy pricingStrategy_ + IPerpPricer oracle_ ) public initializer { // initialize dependencies __ERC20_init(name, symbol); @@ -183,22 +188,22 @@ contract BillBroker is perpUnitAmt = 10 ** IERC20MetadataUpgradeable(address(perp_)).decimals(); updateKeeper(owner()); - updatePricingStrategy(pricingStrategy_); + updateOracle(oracle_); updateFees( BillBrokerFees({ mintFeePerc: 0, burnFeePerc: 0, - perpToUSDSwapFeePercs: Range({ lower: ONE, upper: ONE }), - usdToPerpSwapFeePercs: Range({ lower: ONE, upper: ONE }), + perpToUSDSwapFeeFactors: Range({ lower: ONE, upper: ONE }), + usdToPerpSwapFeeFactors: Range({ lower: ONE, upper: ONE }), protocolSwapSharePerc: 0 }) ); updateARBounds( // Soft bound - Range({ lower: 0, upper: type(uint256).max }), + Range({ lower: 0, upper: MAX_ASSET_RATIO }), // Hard bound - Range({ lower: 0, upper: type(uint256).max }) + Range({ lower: 0, upper: MAX_ASSET_RATIO }) ); } @@ -211,15 +216,13 @@ contract BillBroker is keeper = keeper_; } - /// @notice Updates the reference to the pricing strategy. - /// @param pricingStrategy_ The address of the new pricing strategy. - function updatePricingStrategy( - ISpotPricingStrategy pricingStrategy_ - ) public onlyOwner { - if (pricingStrategy_.decimals() != DECIMALS) { + /// @notice Updates the reference to the oracle. + /// @param oracle_ The address of the new oracle. + function updateOracle(IPerpPricer oracle_) public onlyOwner { + if (oracle_.decimals() != DECIMALS) { revert UnexpectedDecimals(); } - pricingStrategy = pricingStrategy_; + oracle = oracle_; } /// @notice Updates the system fees. @@ -228,13 +231,27 @@ contract BillBroker is if ( fees_.mintFeePerc > ONE || fees_.burnFeePerc > ONE || - fees_.perpToUSDSwapFeePercs.lower > fees_.perpToUSDSwapFeePercs.upper || - fees_.usdToPerpSwapFeePercs.lower > fees_.usdToPerpSwapFeePercs.upper || fees_.protocolSwapSharePerc > ONE ) { revert InvalidPerc(); } + if ( + fees_.perpToUSDSwapFeeFactors.lower > fees_.perpToUSDSwapFeeFactors.upper || + fees_.perpToUSDSwapFeeFactors.lower < ONE || + fees_.perpToUSDSwapFeeFactors.upper > MAX_FEE_FACTOR + ) { + revert InvalidPerc(); + } + + if ( + fees_.usdToPerpSwapFeeFactors.lower > fees_.usdToPerpSwapFeeFactors.upper || + fees_.usdToPerpSwapFeeFactors.lower < ONE || + fees_.usdToPerpSwapFeeFactors.upper > MAX_FEE_FACTOR + ) { + revert InvalidPerc(); + } + fees = fees_; } @@ -323,15 +340,10 @@ contract BillBroker is uint256 usdAmtIn, uint256 postOpAssetRatioMax ) external nonReentrant whenNotPaused returns (uint256 mintAmt) { - ReserveState memory preOpState = reserveState(); - uint256 preOpAssetRatio = assetRatio(preOpState); + ReserveState memory s = reserveState(); + uint256 preOpAssetRatio = assetRatio(s); uint256 postOpAssetRatio = assetRatio( - ReserveState({ - usdBalance: preOpState.usdBalance + usdAmtIn, - perpBalance: preOpState.perpBalance, - usdPrice: preOpState.usdPrice, - perpPrice: preOpState.perpPrice - }) + _updatedReserveState(s, s.usdBalance + usdAmtIn, s.perpBalance) ); // We allow minting only pool is underweight usd @@ -339,7 +351,7 @@ contract BillBroker is return 0; } - mintAmt = computeMintAmtWithUSD(usdAmtIn, preOpState); + mintAmt = computeMintAmtWithUSD(usdAmtIn, s); if (mintAmt <= 0) { return 0; } @@ -354,7 +366,7 @@ contract BillBroker is _mint(msg.sender, mintAmt); // Emit deposit info - emit DepositUSD(usdAmtIn, preOpState); + emit DepositUSD(usdAmtIn, s); } /// @notice Single sided perp token deposit and mint LP tokens. @@ -365,15 +377,10 @@ contract BillBroker is uint256 perpAmtIn, uint256 postOpAssetRatioMin ) external nonReentrant whenNotPaused returns (uint256 mintAmt) { - ReserveState memory preOpState = reserveState(); - uint256 preOpAssetRatio = assetRatio(preOpState); + ReserveState memory s = reserveState(); + uint256 preOpAssetRatio = assetRatio(s); uint256 postOpAssetRatio = assetRatio( - ReserveState({ - usdBalance: preOpState.usdBalance, - perpBalance: preOpState.perpBalance + perpAmtIn, - usdPrice: preOpState.usdPrice, - perpPrice: preOpState.perpPrice - }) + _updatedReserveState(s, s.usdBalance, s.perpBalance + perpAmtIn) ); // We allow minting only pool is underweight perp @@ -381,7 +388,7 @@ contract BillBroker is return 0; } - mintAmt = computeMintAmtWithPerp(perpAmtIn, preOpState); + mintAmt = computeMintAmtWithPerp(perpAmtIn, s); if (mintAmt <= 0) { return 0; } @@ -396,7 +403,7 @@ contract BillBroker is _mint(msg.sender, mintAmt); // Emit deposit info - emit DepositPerp(perpAmtIn, preOpState); + emit DepositPerp(perpAmtIn, s); } /// @notice Burns LP tokens and redeems usd and perp tokens. @@ -433,12 +440,9 @@ contract BillBroker is uint256 perpAmtMin ) external nonReentrant whenNotPaused returns (uint256 perpAmtOut) { // compute perp amount out - ReserveState memory preOpState = reserveState(); + ReserveState memory s = reserveState(); uint256 protocolFeePerpAmt; - (perpAmtOut, , protocolFeePerpAmt) = computeUSDToPerpSwapAmt( - usdAmtIn, - preOpState - ); + (perpAmtOut, protocolFeePerpAmt) = computeUSDToPerpSwapAmt(usdAmtIn, s); if (usdAmtIn <= 0 || perpAmtOut <= 0) { revert UnacceptableSwap(); } @@ -458,7 +462,7 @@ contract BillBroker is perp.safeTransfer(msg.sender, perpAmtOut); // Emit swap info - emit SwapUSDForPerps(usdAmtIn, preOpState); + emit SwapUSDForPerps(usdAmtIn, s); } /// @notice Swaps perp tokens from the user for usd tokens from the reserve. @@ -470,9 +474,9 @@ contract BillBroker is uint256 usdAmtMin ) external nonReentrant whenNotPaused returns (uint256 usdAmtOut) { // Compute swap amount - ReserveState memory preOpState = reserveState(); + ReserveState memory s = reserveState(); uint256 protocolFeeUsdAmt; - (usdAmtOut, , protocolFeeUsdAmt) = computePerpToUSDSwapAmt(perpAmtIn, preOpState); + (usdAmtOut, protocolFeeUsdAmt) = computePerpToUSDSwapAmt(perpAmtIn, s); if (perpAmtIn <= 0 || usdAmtOut <= 0) { revert UnacceptableSwap(); } @@ -492,7 +496,7 @@ contract BillBroker is usd.safeTransfer(msg.sender, usdAmtOut); // Emit swap info - emit SwapPerpsForUSD(perpAmtIn, preOpState); + emit SwapPerpsForUSD(perpAmtIn, s); } //----------------------------------------------------------------------------- @@ -521,7 +525,7 @@ contract BillBroker is function computePerpToUSDSwapAmt( uint256 perpAmtIn ) public returns (uint256 usdAmtOut) { - (usdAmtOut, , ) = computePerpToUSDSwapAmt(perpAmtIn, reserveState()); + (usdAmtOut, ) = computePerpToUSDSwapAmt(perpAmtIn, reserveState()); } /// @notice Computes the amount of perp tokens swapped out, @@ -531,7 +535,7 @@ contract BillBroker is function computeUSDToPerpSwapAmt( uint256 usdAmtIn ) public returns (uint256 perpAmtOut) { - (perpAmtOut, , ) = computeUSDToPerpSwapAmt(usdAmtIn, reserveState()); + (perpAmtOut, ) = computeUSDToPerpSwapAmt(usdAmtIn, reserveState()); } /// @return s The reserve usd and perp token balances and prices. @@ -545,20 +549,20 @@ contract BillBroker is }); } - /// @dev Reverts if the pricing strategy returns an invalid price. - /// @return The price of usd tokens from the pricing strategy. + /// @dev Reverts if the oracle returns an invalid price. + /// @return The price of usd tokens from the oracle. function usdPrice() public returns (uint256) { - (uint256 p, bool v) = pricingStrategy.usdPrice(); + (uint256 p, bool v) = oracle.usdPrice(); if (!v) { revert UnreliablePrice(); } return p; } - /// @dev Reverts if the pricing strategy returns an invalid price. - /// @return The price of perp tokens from the pricing strategy. + /// @dev Reverts if the oracle returns an invalid price. + /// @return The price of perp tokens from the oracle. function perpPrice() public returns (uint256) { - (uint256 p, bool v) = pricingStrategy.perpPrice(); + (uint256 p, bool v) = oracle.perpFmvUsdPrice(); if (!v) { revert UnreliablePrice(); } @@ -647,22 +651,39 @@ contract BillBroker is function computeMintAmtWithUSD( uint256 usdAmtIn, ReserveState memory s - ) public view returns (uint256) { + ) public view returns (uint256 mintAmt) { if (usdAmtIn <= 0) { return 0; } + // We compute equal value of perp tokens going out. + uint256 totalSupply_ = totalSupply(); uint256 valueIn = s.usdPrice.mulDiv(usdAmtIn, usdUnitAmt); uint256 totalReserveVal = (s.usdPrice.mulDiv(s.usdBalance, usdUnitAmt) + s.perpPrice.mulDiv(s.perpBalance, perpUnitAmt)); + if (totalReserveVal == 0 || totalSupply_ == 0) { + return 0; + } - return - (totalReserveVal > 0) - ? valueIn.mulDiv(totalSupply(), totalReserveVal).mulDiv( - ONE - fees.mintFeePerc, - ONE - ) - : 0; + // Compute mint amount. + mintAmt = valueIn.mulDiv(totalSupply_, totalReserveVal); + + // A single sided deposit is a combination of swap and mint. + // We first calculate the amount of usd swapped into perps and + // apply the swap fee only for that portion. + // The mint fees are waived, because single sided deposits + // push the pool back into balance. + uint256 percOfAmtInSwapped = ONE.mulDiv( + usdAmtIn - (s.usdBalance + usdAmtIn).mulDiv(mintAmt, totalSupply_), + usdAmtIn + ); + uint256 feeFactor = computeUSDToPerpSwapFeeFactor( + assetRatio(s), + assetRatio(_updatedReserveState(s, s.usdBalance + usdAmtIn, s.perpBalance)) + ); + mintAmt = + mintAmt.mulDiv(percOfAmtInSwapped, ONE).mulDiv(TWO - feeFactor, ONE) + + mintAmt.mulDiv(ONE - percOfAmtInSwapped, ONE); } /// @notice Computes the amount of LP tokens minted, @@ -673,22 +694,41 @@ contract BillBroker is function computeMintAmtWithPerp( uint256 perpAmtIn, ReserveState memory s - ) public view returns (uint256) { + ) public view returns (uint256 mintAmt) { if (perpAmtIn <= 0) { return 0; } + // We compute equal value of perp tokens coming in. + uint256 totalSupply_ = totalSupply(); uint256 valueIn = s.perpPrice.mulDiv(perpAmtIn, perpUnitAmt); uint256 totalReserveVal = (s.usdPrice.mulDiv(s.usdBalance, usdUnitAmt) + s.perpPrice.mulDiv(s.perpBalance, perpUnitAmt)); + if (totalReserveVal == 0 || totalSupply_ == 0) { + return 0; + } - return - (totalReserveVal > 0) - ? valueIn.mulDiv(totalSupply(), totalReserveVal).mulDiv( - ONE - fees.mintFeePerc, - ONE - ) - : 0; + // Compute mint amount. + mintAmt = (totalReserveVal > 0) + ? valueIn.mulDiv(totalSupply_, totalReserveVal) + : 0; + + // A single sided deposit is a combination of swap and mint. + // We first calculate the amount of perps swapped into usd and + // apply the swap fee only for that portion. + // The mint fees are waived, because single sided deposits + // push the pool back into balance. + uint256 percOfAmtInSwapped = ONE.mulDiv( + perpAmtIn - (s.perpBalance + perpAmtIn).mulDiv(mintAmt, totalSupply_), + perpAmtIn + ); + uint256 feeFactor = computePerpToUSDSwapFeeFactor( + assetRatio(s), + assetRatio(_updatedReserveState(s, s.usdBalance, s.perpBalance + perpAmtIn)) + ); + mintAmt = + mintAmt.mulDiv(percOfAmtInSwapped, ONE).mulDiv(TWO - feeFactor, ONE) + + mintAmt.mulDiv(ONE - percOfAmtInSwapped, ONE); } /// @notice Computes the amount of usd and perp tokens redeemed, @@ -720,41 +760,34 @@ contract BillBroker is /// @param s The current reserve state. /// @dev Quoted usd token amount out includes the fees withheld. /// @return usdAmtOut The amount of usd tokens swapped out. - /// @return lpFeeUsdAmt The amount of usd tokens charged as swap fees by LPs. /// @return protocolFeeUsdAmt The amount of usd tokens charged as protocol fees. function computePerpToUSDSwapAmt( uint256 perpAmtIn, ReserveState memory s - ) - public - view - returns (uint256 usdAmtOut, uint256 lpFeeUsdAmt, uint256 protocolFeeUsdAmt) - { - // We compute equal value of usd tokens out given perp tokens in. + ) public view returns (uint256 usdAmtOut, uint256 protocolFeeUsdAmt) { + // We compute equal value tokens to swap out. usdAmtOut = perpAmtIn.mulDiv(s.perpPrice, s.usdPrice).mulDiv( usdUnitAmt, perpUnitAmt ); - // We compute the total fee percentage, lp fees and protocol fees - uint256 totalFeePerc = computePerpToUSDSwapFeePerc( + // We compute the fee factor + uint256 feeFactor = computePerpToUSDSwapFeeFactor( assetRatio(s), assetRatio( - ReserveState({ - usdBalance: s.usdBalance - usdAmtOut, - perpBalance: s.perpBalance + perpAmtIn, - usdPrice: s.usdPrice, - perpPrice: s.perpPrice - }) + _updatedReserveState( + s, + s.usdBalance - usdAmtOut, + s.perpBalance + perpAmtIn + ) ) ); - if (totalFeePerc >= ONE) { - return (0, 0, 0); + if (feeFactor >= ONE) { + protocolFeeUsdAmt = usdAmtOut + .mulDiv(feeFactor - ONE, ONE, MathUpgradeable.Rounding.Up) + .mulDiv(fees.protocolSwapSharePerc, ONE, MathUpgradeable.Rounding.Up); } - uint256 totalFeeUsdAmt = usdAmtOut.mulDiv(totalFeePerc, ONE); - usdAmtOut -= totalFeeUsdAmt; - protocolFeeUsdAmt = totalFeeUsdAmt.mulDiv(fees.protocolSwapSharePerc, ONE); - lpFeeUsdAmt = totalFeeUsdAmt - protocolFeeUsdAmt; + usdAmtOut = usdAmtOut.mulDiv(TWO - feeFactor, ONE); } /// @notice Computes the amount of perp tokens swapped out, @@ -763,149 +796,126 @@ contract BillBroker is /// @param s The current reserve state. /// @dev Quoted perp token amount out includes the fees withheld. /// @return perpAmtOut The amount of perp tokens swapped out. - /// @return lpFeePerpAmt The amount of perp tokens charged as swap fees by LPs. /// @return protocolFeePerpAmt The amount of perp tokens charged as protocol fees. function computeUSDToPerpSwapAmt( uint256 usdAmtIn, ReserveState memory s - ) - public - view - returns (uint256 perpAmtOut, uint256 lpFeePerpAmt, uint256 protocolFeePerpAmt) - { - // We compute equal value of perp tokens out given usd tokens in. + ) public view returns (uint256 perpAmtOut, uint256 protocolFeePerpAmt) { + // We compute equal value tokens to swap out. perpAmtOut = usdAmtIn.mulDiv(s.usdPrice, s.perpPrice).mulDiv( perpUnitAmt, usdUnitAmt ); - // We compute the total fee percentage, lp fees and protocol fees - uint256 totalFeePerc = computeUSDToPerpSwapFeePerc( + + // We compute the fee factor + uint256 feeFactor = computeUSDToPerpSwapFeeFactor( assetRatio(s), assetRatio( - ReserveState({ - usdBalance: s.usdBalance + usdAmtIn, - perpBalance: s.perpBalance - perpAmtOut, - usdPrice: s.usdPrice, - perpPrice: s.perpPrice - }) + _updatedReserveState( + s, + s.usdBalance + usdAmtIn, + s.perpBalance - perpAmtOut + ) ) ); - if (totalFeePerc >= ONE) { - return (0, 0, 0); + if (feeFactor >= ONE) { + protocolFeePerpAmt = perpAmtOut + .mulDiv(feeFactor - ONE, ONE, MathUpgradeable.Rounding.Up) + .mulDiv(fees.protocolSwapSharePerc, ONE, MathUpgradeable.Rounding.Up); } - uint256 totalFeePerpAmt = perpAmtOut.mulDiv(totalFeePerc, ONE); - perpAmtOut -= totalFeePerpAmt; - protocolFeePerpAmt = totalFeePerpAmt.mulDiv(fees.protocolSwapSharePerc, ONE); - lpFeePerpAmt = totalFeePerpAmt - protocolFeePerpAmt; + perpAmtOut = perpAmtOut.mulDiv(TWO - feeFactor, ONE); } - /// @notice Computes the swap fee percentage when swapping from perp to usd tokens. + /// @notice Computes the swap fee factor when swapping from perp to usd tokens. /// @dev Swapping from perp to usd tokens, leaves the system with more perp and fewer usd tokens /// thereby decreasing the system's `assetRatio`. Thus arPost < arPre. /// @param arPre The asset ratio of the system before swapping. /// @param arPost The asset ratio of the system after swapping. - /// @return The fee percentage. - function computePerpToUSDSwapFeePerc( + /// @return The fee factor. + function computePerpToUSDSwapFeeFactor( uint256 arPre, uint256 arPost ) public view returns (uint256) { - if (arPost > arPre) { - revert UnexpectedARDelta(); + // When the ar decreases below the lower bound swaps are halted. + // Fees are set to 100% or a fee factor of 2.0 + if (arPost < arHardBound.lower) { + return TWO; } - // When the ar decreases below the lower bound, - // swaps are effectively halted by setting fees to 100%. - if (arPost < arHardBound.lower) { - return ONE; - } - // When the ar is between the soft and hard bound, a linear function is applied. - // When the ar is above the soft bound, a flat percentage fee is applied. - // - // fee - // ^ - // | - // fh | \ | - // | \ | - // | \ | - // | \ | - // | \ | - // | \ | - // fl | \__________ - // | | - // | | - // | | - // +---------------------------> ar - // arHL arSL 1.0 - // - Range memory swapFeePercs = fees.perpToUSDSwapFeePercs; + Range memory feeP2U = fees.perpToUSDSwapFeeFactors; + // The maximum -ve fee, inferred from fees for the other swap direction. + uint256 feeU2PUpperInv = (TWO - fees.usdToPerpSwapFeeFactors.upper); return - _computeFeePerc( - Line({ - x1: arHardBound.lower, - y1: swapFeePercs.upper, - x2: arSoftBound.lower, - y2: swapFeePercs.lower - }), - Line({ x1: 0, y1: swapFeePercs.lower, x2: ONE, y2: swapFeePercs.lower }), - arPost, - arPre, - arSoftBound.lower - ); - } - - /// @notice Computes the swap fee percentage when swapping from usd to perp tokens. + LineHelpers + .computePiecewiseAvgY( + Line({ + x1: arHardBound.lower, + y1: feeP2U.upper, + x2: arSoftBound.lower, + y2: feeP2U.lower + }), + Line({ + x1: arSoftBound.lower, + y1: feeP2U.lower, + x2: arSoftBound.upper, + y2: feeP2U.lower + }), + Line({ + x1: arSoftBound.upper, + y1: feeP2U.lower, + x2: arHardBound.upper, + y2: feeU2PUpperInv + }), + arSoftBound, + Range({ lower: arPost, upper: arPre }) + ) + .clip(feeU2PUpperInv, feeP2U.upper); + } + + /// @notice Computes the swap fee factor when swapping from usd to perp tokens. /// @dev Swapping from usd to perp tokens, leaves the system with more usd and fewer perp tokens /// thereby increasing the system's `assetRatio`. Thus arPost > arPre. /// @param arPre The asset ratio of the system before swapping. /// @param arPost The asset ratio of the system after swapping. - /// @return The fee percentage. - function computeUSDToPerpSwapFeePerc( + /// @return The fee factor. + function computeUSDToPerpSwapFeeFactor( uint256 arPre, uint256 arPost ) public view returns (uint256) { - if (arPost < arPre) { - revert UnexpectedARDelta(); + // When the ar increases above the hard bound, swaps are halted. + // Fees are set to 100% or a fee factor of 2.0 + if (arPost > arHardBound.upper) { + return TWO; } - // When the ar increases above the hard bound, - // swaps are effectively halted by setting fees to 100%. - if (arPost > arHardBound.upper) { - return ONE; - } - - // When the ar is between the soft and hard bound, a linear function is applied. - // When the ar is below the soft bound, a flat percentage fee is applied. - // - // fee - // ^ - // | - // fh | | / - // | | / - // | | / - // | | / - // | | / - // | | / - // fl | __________/ - // | | - // | | - // | | - // +---------------------------> ar - // 1.0 arSU arHU - // - Range memory swapFeePercs = fees.usdToPerpSwapFeePercs; + Range memory feeU2P = fees.usdToPerpSwapFeeFactors; + // The maximum -ve fee, inferred from fees for the other swap direction. + uint256 feeP2UUpperInv = (TWO - fees.perpToUSDSwapFeeFactors.upper); return - _computeFeePerc( - Line({ x1: 0, y1: swapFeePercs.lower, x2: ONE, y2: swapFeePercs.lower }), - Line({ - x1: arSoftBound.upper, - y1: swapFeePercs.lower, - x2: arHardBound.upper, - y2: swapFeePercs.upper - }), - arPre, - arPost, - arSoftBound.upper - ); + LineHelpers + .computePiecewiseAvgY( + Line({ + x1: arHardBound.lower, + y1: feeP2UUpperInv, + x2: arSoftBound.lower, + y2: feeU2P.lower + }), + Line({ + x1: arSoftBound.lower, + y1: feeU2P.lower, + x2: arSoftBound.upper, + y2: feeU2P.lower + }), + Line({ + x1: arSoftBound.upper, + y1: feeU2P.lower, + x2: arHardBound.upper, + y2: feeU2P.upper + }), + arSoftBound, + Range({ lower: arPre, upper: arPost }) + ) + .clip(feeP2UUpperInv, feeU2P.upper); } /// @param s The system reserve state. @@ -919,7 +929,7 @@ contract BillBroker is s.perpBalance.mulDiv(s.perpPrice, perpUnitAmt) ) ) - : type(uint256).max; + : MAX_ASSET_RATIO; } /// @notice The address which holds any revenue extracted by protocol. @@ -931,44 +941,18 @@ contract BillBroker is //----------------------------------------------------------------------------- // Private methods - /// @dev The function assumes the fee curve is defined as a pair-wise linear function which merge at the cutoff point. - /// The swap fee is computed as avg height of the fee curve between {arL,arU}. - function _computeFeePerc( - Line memory fn1, - Line memory fn2, - uint256 arL, - uint256 arU, - uint256 cutoff - ) private pure returns (uint256 feePerc) { - if (arU <= cutoff) { - feePerc = _avgY(fn1, arL, arU); - } else if (arL >= cutoff) { - feePerc = _avgY(fn2, arL, arU); - } else { - feePerc = (_avgY(fn1, arL, cutoff).mulDiv(cutoff - arL, arU - arL) + - _avgY(fn2, cutoff, arU).mulDiv(arU - cutoff, arU - arL)); - } - feePerc = MathUpgradeable.min(feePerc, ONE); - } - - /// @dev We compute the average height of the line between {xL,xU}. - function _avgY( - Line memory fn, - uint256 xL, - uint256 xU - ) private pure returns (uint256) { - // if the line has a zero slope, return any y - if (fn.y1 == fn.y2) { - return fn.y2; - } - - // m = dlY/dlX - // c = y2 - m . x2 - // Avg height => (yL + yU) / 2 - // => m . ( xL + xU ) / 2 + c - int256 dlY = fn.y2.toInt256() - fn.y1.toInt256(); - int256 dlX = fn.x2.toInt256() - fn.x1.toInt256(); - int256 c = fn.y2.toInt256() - ((fn.x2.toInt256() * dlY) / dlX); - return ((((xL + xU).toInt256() * dlY) / (2 * dlX)) + c).abs(); + /// @dev Constructs the new reserve state based on provided balances. + function _updatedReserveState( + ReserveState memory s, + uint256 usdBalance_, + uint256 perpBalance_ + ) private pure returns (ReserveState memory) { + return + ReserveState({ + usdBalance: usdBalance_, + perpBalance: perpBalance_, + usdPrice: s.usdPrice, + perpPrice: s.perpPrice + }); } } diff --git a/spot-vaults/contracts/UsdcSpotManager.sol b/spot-vaults/contracts/UsdcSpotManager.sol deleted file mode 100644 index 05d985b3..00000000 --- a/spot-vaults/contracts/UsdcSpotManager.sol +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// solhint-disable-next-line compiler-version -pragma solidity ^0.7.6; -pragma abicoder v2; - -import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; -import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; -import { PositionKey } from "@uniswap/v3-periphery/contracts/libraries/PositionKey.sol"; - -import { ISpotPricingStrategy } from "./_interfaces/ISpotPricingStrategy.sol"; -import { IAlphaProVault } from "./_interfaces/external/IAlphaProVault.sol"; -import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; - -/// @title UsdcSpotManager -/// @notice This contract is a programmatic manager for the USDC-SPOT Charm AlphaProVault. -contract UsdcSpotManager { - /// @dev Token Constants. - uint256 public constant ONE_SPOT = 1e9; - uint256 public constant ONE_USDC = 1e6; - - /// @dev Decimals. - uint256 public constant DECIMALS = 18; - uint256 public constant ONE = (10 ** DECIMALS); - - /// @dev We bound the deviation factor to 100.0. - uint256 public constant MAX_DEVIATION = 100 * ONE; // 100.0 - - //------------------------------------------------------------------------- - // Storage - - /// @notice The USDC-SPOT charm alpha vault. - IAlphaProVault public immutable VAULT; - - /// @notice The underlying USDC-SPOT univ3 pool. - IUniswapV3Pool public immutable POOL; - - /// @notice The vault's token0, the USDC token. - address public immutable USDC; - - /// @notice The vault's token1, the SPOT token. - address public immutable SPOT; - - /// @notice Pricing strategy to price the SPOT token. - ISpotPricingStrategy public pricingStrategy; - - /// @notice The contract owner. - address public owner; - - //------------------------------------------------------------------------- - // Manager storage - - /// @notice The recorded deviation factor at the time of the last successful rebalance operation. - uint256 public prevDeviation; - - //-------------------------------------------------------------------------- - // Modifiers - - modifier onlyOwner() { - // solhint-disable-next-line custom-errors - require(msg.sender == owner, "Unauthorized caller"); - _; - } - - //----------------------------------------------------------------------------- - // Constructor and Initializer - - /// @notice Constructor initializes the contract with provided addresses. - /// @param vault_ Address of the AlphaProVault contract. - /// @param pricingStrategy_ Address of the spot appraiser. - constructor(IAlphaProVault vault_, ISpotPricingStrategy pricingStrategy_) { - owner = msg.sender; - - VAULT = vault_; - POOL = vault_.pool(); - USDC = vault_.token0(); - SPOT = vault_.token1(); - - pricingStrategy = pricingStrategy_; - // solhint-disable-next-line custom-errors - require(pricingStrategy.decimals() == DECIMALS, "Invalid decimals"); - } - - //-------------------------------------------------------------------------- - // Owner only methods - - /// @notice Updates the owner role. - function transferOwnership(address owner_) external onlyOwner { - owner = owner_; - } - - /// @notice Updates the Spot pricing strategy reference. - function updatePricingStrategy( - ISpotPricingStrategy pricingStrategy_ - ) external onlyOwner { - pricingStrategy = pricingStrategy_; - } - - /// @notice Updates the vault's liquidity range parameters. - function setLiquidityRanges( - int24 baseThreshold, - uint24 fullRangeWeight, - int24 limitThreshold - ) external onlyOwner { - // Update liquidity parameters on the vault. - VAULT.setBaseThreshold(baseThreshold); - VAULT.setFullRangeWeight(fullRangeWeight); - VAULT.setLimitThreshold(limitThreshold); - } - - /// @notice Forwards the given calldata to the vault. - /// @param callData The calldata to pass to the vault. - /// @return The data returned by the vault method call. - function execOnVault( - bytes calldata callData - ) external onlyOwner returns (bytes memory) { - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory r) = address(VAULT).call(callData); - // solhint-disable-next-line custom-errors - require(success, "Vault call failed"); - return r; - } - - //-------------------------------------------------------------------------- - // External write methods - - /// @notice Executes vault rebalance. - function rebalance() public { - (uint256 deviation, bool deviationValid) = computeDeviationFactor(); - - // We rebalance if the deviation factor has crossed ONE (in either direction). - bool forceLiquidityUpdate = ((deviation <= ONE && prevDeviation > ONE) || - (deviation >= ONE && prevDeviation < ONE)); - - // Execute rebalance. - // NOTE: the vault.rebalance() will revert if enough time has not elapsed. - // We thus override with a force rebalance. - // https://learn.charm.fi/charm/technical-references/core/alphaprovault#rebalance - forceLiquidityUpdate ? _execForceRebalance() : VAULT.rebalance(); - - // We only activate the limit range liquidity, when - // the vault sells SPOT and deviation is above ONE, or when - // the vault buys SPOT and deviation is below ONE - bool extraSpot = isOverweightSpot(); - bool activeLimitRange = deviationValid && - ((deviation >= ONE && extraSpot) || (deviation <= ONE && !extraSpot)); - - // Trim positions after rebalance. - if (!activeLimitRange) { - _removeLimitLiquidity(); - } - - // Update rebalance state. - prevDeviation = deviation; - } - - /// @notice Computes the deviation between SPOT's market price and it's FMV price. - /// @return The computed deviation factor. - function computeDeviationFactor() public returns (uint256, bool) { - uint256 spotMarketPrice = getSpotUSDPrice(); - (uint256 spotTargetPrice, bool spotTargetPriceValid) = pricingStrategy - .perpPrice(); - (, bool usdcPriceValid) = pricingStrategy.usdPrice(); - bool deviationValid = (spotTargetPriceValid && usdcPriceValid); - uint256 deviation = spotTargetPrice > 0 - ? FullMath.mulDiv(spotMarketPrice, ONE, spotTargetPrice) - : type(uint256).max; - deviation = (deviation > MAX_DEVIATION) ? MAX_DEVIATION : deviation; - return (deviation, deviationValid); - } - - //----------------------------------------------------------------------------- - // External Public view methods - - /// @return The computed SPOT price in USD from the underlying univ3 pool. - function getSpotUSDPrice() public view returns (uint256) { - uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(VAULT.getTwap()); - uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; - uint256 usdcPerSpot = FullMath.mulDiv(ONE, (1 << 192), ratioX192); - return FullMath.mulDiv(usdcPerSpot, ONE_SPOT, ONE_USDC); - } - - /// @notice Checks the vault is overweight SPOT, and looking to sell the extra SPOT for USDC. - function isOverweightSpot() public view returns (bool) { - // NOTE: This assumes that in the underlying univ3 pool and - // token0 is USDC and token1 is SPOT. - int24 _marketPrice = VAULT.getTwap(); - int24 _limitLower = VAULT.limitLower(); - int24 _limitUpper = VAULT.limitUpper(); - int24 _limitPrice = (_limitLower + _limitUpper) / 2; - // The limit range has more token1 than token0 if `_marketPrice >= _limitPrice`, - // so the vault looks to sell token1. - return (_marketPrice >= _limitPrice); - } - - /// @return Number of decimals representing 1.0. - function decimals() external pure returns (uint8) { - return uint8(DECIMALS); - } - - //----------------------------------------------------------------------------- - // Private methods - - /// @dev A low-level method, which interacts directly with the vault and executes - /// a rebalance even when enough time hasn't elapsed since the last rebalance. - function _execForceRebalance() private { - uint32 _period = VAULT.period(); - VAULT.setPeriod(0); - VAULT.rebalance(); - VAULT.setPeriod(_period); - } - - /// @dev Removes the vault's limit range liquidity. - /// To be invoked right after a rebalance operation, as it assumes that - /// the vault has a active limit range liquidity. - function _removeLimitLiquidity() private { - int24 _limitLower = VAULT.limitLower(); - int24 _limitUpper = VAULT.limitUpper(); - (uint128 limitLiquidity, , , , ) = _position(_limitLower, _limitUpper); - // docs: https://learn.charm.fi/charm/technical-references/core/alphaprovault#emergencyburn - VAULT.emergencyBurn(_limitLower, _limitUpper, limitLiquidity); - } - - /// @dev Wrapper around `IUniswapV3Pool.positions()`. - function _position( - int24 tickLower, - int24 tickUpper - ) private view returns (uint128, uint256, uint256, uint128, uint128) { - bytes32 positionKey = PositionKey.compute(address(VAULT), tickLower, tickUpper); - return POOL.positions(positionKey); - } -} diff --git a/spot-vaults/contracts/WethWamplManager.sol b/spot-vaults/contracts/WethWamplManager.sol deleted file mode 100644 index b51cc16c..00000000 --- a/spot-vaults/contracts/WethWamplManager.sol +++ /dev/null @@ -1,431 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// solhint-disable-next-line compiler-version -pragma solidity ^0.7.6; -pragma abicoder v2; - -import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; -import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; -import { PositionKey } from "@uniswap/v3-periphery/contracts/libraries/PositionKey.sol"; -import { SafeCast } from "@uniswap/v3-core/contracts/libraries/SafeCast.sol"; - -import { IAlphaProVault } from "./_interfaces/external/IAlphaProVault.sol"; -import { IChainlinkOracle } from "./_interfaces/external/IChainlinkOracle.sol"; -import { IAmpleforthOracle } from "./_interfaces/external/IAmpleforthOracle.sol"; -import { IWAMPL } from "./_interfaces/external/IWAMPL.sol"; -import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; - -/// @title WethWamplManager -/// @notice This contract is a programmatic manager for the WETH-WAMPL Charm AlphaProVault. -contract WethWamplManager { - /// @dev Constants for AMPL and WAMPL units and supply limits. - uint256 public constant ONE_AMPL = 1e9; - uint256 public constant ONE_WAMPL = 1e18; - - /// @dev Decimals. - uint256 public constant DECIMALS = 18; - uint256 public constant ONE = (10 ** DECIMALS); - - /// @dev At all times active liquidity percentage is no lower than 20%. - uint256 public constant MIN_ACTIVE_LIQ_PERC = ONE / 5; // 20% - - /// @dev We bound the deviation factor to 100.0. - uint256 public constant MAX_DEVIATION = 100 * ONE; // 100.0 - - /// @dev Oracle constants. - uint256 public constant CL_ORACLE_STALENESS_THRESHOLD_SEC = 3600 * 24; // 1 day - - //------------------------------------------------------------------------- - // Storage - - /// @notice The WETH-WAMPL charm alpha vault. - IAlphaProVault public immutable VAULT; - - /// @notice The underlying WETH-WAMPL univ3 pool. - IUniswapV3Pool public immutable POOL; - - /// @notice The vault's token0, the WETH token. - address public immutable WETH; - - /// @notice The vault's token1, the WAMPL token. - IWAMPL public immutable WAMPL; - - /// @notice The cpi oracle which returns AMPL's price target in USD. - IAmpleforthOracle public cpiOracle; - - /// @notice The chainlink oracle which returns ETH's current USD price. - IChainlinkOracle public ethOracle; - - /// @notice The contract owner. - address public owner; - - //------------------------------------------------------------------------- - // Active percentage calculation parameters - // - // The deviation factor (or deviation) is defined as the ratio between - // AMPL's current market price and its target price. - // The deviation is 1.0, when AMPL is at the target. - // - // The active liquidity percentage (a value between 20% to 100%) - // is computed based on pair-wise linear function, defined by the contract owner. - // - // If the current deviation is below ONE, function f1 is used - // else function f2 is used. Both f1 and f2 are defined by the owner. - // They are lines, with 2 {x,y} coordinates. The x coordinates are deviation factors, - // and y coordinates are active liquidity percentages. - // - // Both deviation and active liquidity percentage and represented internally - // as a fixed-point number with {DECIMALS} places. - // - - /// @notice A data structure to define a geometric Line with two points. - struct Line { - // x-coordinate of the first point. - uint256 x1; - // y-coordinate of the first point. - uint256 y1; - // x-coordinate of the second point. - uint256 x2; - // y-coordinate of the second point. - uint256 y2; - } - - /// @notice Active percentage calculation function for when deviation is below ONE. - Line public activeLiqPercFn1; - - /// @notice Active percentage calculation function for when deviation is above ONE. - Line public activeLiqPercFn2; - - //------------------------------------------------------------------------- - // Manager parameters - - /// @notice The delta between the current and last recorded active liquidity percentage values - /// outside which a rebalance is executed forcefully. - uint256 public tolerableActiveLiqPercDelta; - - //------------------------------------------------------------------------- - // Manager storage - - /// @notice The recorded deviation factor at the time of the last successful rebalance operation. - uint256 public prevDeviation; - - //-------------------------------------------------------------------------- - // Modifiers - - modifier onlyOwner() { - // solhint-disable-next-line custom-errors - require(msg.sender == owner, "Unauthorized caller"); - _; - } - - //----------------------------------------------------------------------------- - // Constructor and Initializer - - /// @notice Constructor initializes the contract with provided addresses. - /// @param vault_ Address of the AlphaProVault contract. - /// @param cpiOracle_ Address of the Ampleforth CPI oracle contract. - /// @param ethOracle_ Address of the Chainlink ETH price oracle contract. - constructor( - IAlphaProVault vault_, - IAmpleforthOracle cpiOracle_, - IChainlinkOracle ethOracle_ - ) { - owner = msg.sender; - - VAULT = vault_; - POOL = vault_.pool(); - WETH = vault_.token0(); - WAMPL = IWAMPL(vault_.token1()); - - cpiOracle = cpiOracle_; - ethOracle = ethOracle_; - - activeLiqPercFn1 = Line({ - x1: ONE / 2, // 0.5 - y1: ONE / 5, // 20% - x2: ONE, // 1.0 - y2: ONE // 100% - }); - activeLiqPercFn2 = Line({ - x1: ONE, // 1.0 - y1: ONE, // 100% - x2: ONE * 2, // 2.0 - y2: ONE / 5 // 20% - }); - - tolerableActiveLiqPercDelta = ONE / 10; // 10% - prevDeviation = 0; - } - - //-------------------------------------------------------------------------- - // Owner only methods - - /// @notice Updates the owner role. - function transferOwnership(address owner_) external onlyOwner { - owner = owner_; - } - - /// @notice Updates the ampleforth cpi oracle. - function setCpiOracle(IAmpleforthOracle cpiOracle_) external onlyOwner { - cpiOracle = cpiOracle_; - } - - /// @notice Updates the chainlink eth usd price oracle. - function setEthOracle(IChainlinkOracle ethOracle_) external onlyOwner { - ethOracle = ethOracle_; - } - - /// @notice Updates the active liquidity percentage calculation parameters. - function setActivePercParams( - uint256 tolerableActiveLiqPercDelta_, - Line memory activeLiqPercFn1_, - Line memory activeLiqPercFn2_ - ) external onlyOwner { - tolerableActiveLiqPercDelta = tolerableActiveLiqPercDelta_; - activeLiqPercFn1 = activeLiqPercFn1_; - activeLiqPercFn2 = activeLiqPercFn2_; - } - - /// @notice Updates the vault's liquidity range parameters. - function setLiquidityRanges( - int24 baseThreshold, - uint24 fullRangeWeight, - int24 limitThreshold - ) external onlyOwner { - // Update liquidity parameters on the vault. - VAULT.setBaseThreshold(baseThreshold); - VAULT.setFullRangeWeight(fullRangeWeight); - VAULT.setLimitThreshold(limitThreshold); - } - - /// @notice Forwards the given calldata to the vault. - /// @param callData The calldata to pass to the vault. - /// @return The data returned by the vault method call. - function execOnVault( - bytes calldata callData - ) external onlyOwner returns (bytes memory) { - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory r) = address(VAULT).call(callData); - // solhint-disable-next-line custom-errors - require(success, "Vault call failed"); - return r; - } - - //-------------------------------------------------------------------------- - // External write methods - - /// @notice Executes vault rebalance. - function rebalance() public { - // Get the current deviation factor. - (uint256 deviation, bool deviationValid) = computeDeviationFactor(); - - // Calculate the current active liquidity percentage. - uint256 activeLiqPerc = deviationValid - ? computeActiveLiqPerc(deviation) - : MIN_ACTIVE_LIQ_PERC; - - // We have to rebalance out of turn - // - if the active liquidity perc has deviated significantly, or - // - if the deviation factor has crossed ONE (in either direction). - uint256 prevActiveLiqPerc = computeActiveLiqPerc(prevDeviation); - uint256 activeLiqPercDelta = (activeLiqPerc > prevActiveLiqPerc) - ? activeLiqPerc - prevActiveLiqPerc - : prevActiveLiqPerc - activeLiqPerc; - bool forceLiquidityUpdate = (activeLiqPercDelta > tolerableActiveLiqPercDelta) || - ((deviation <= ONE && prevDeviation > ONE) || - (deviation >= ONE && prevDeviation < ONE)); - - // Execute rebalance. - // NOTE: the vault.rebalance() will revert if enough time has not elapsed. - // We thus override with a force rebalance. - // https://learn.charm.fi/charm/technical-references/core/alphaprovault#rebalance - forceLiquidityUpdate ? _execForceRebalance() : VAULT.rebalance(); - - // We only activate the limit range liquidity, when - // the vault sells WAMPL and deviation is above ONE, or when - // the vault buys WAMPL and deviation is below ONE - bool extraWampl = isOverweightWampl(); - bool activeLimitRange = deviationValid && - ((deviation >= ONE && extraWampl) || (deviation <= ONE && !extraWampl)); - - // Trim positions after rebalance. - _trimLiquidity(activeLiqPerc, activeLimitRange); - - // Update rebalance state. - prevDeviation = deviation; - } - - /// @notice Computes the deviation between AMPL's market price and target. - /// @return The computed deviation factor. - function computeDeviationFactor() public returns (uint256, bool) { - (uint256 ethUSDPrice, bool ethPriceValid) = getEthUSDPrice(); - uint256 marketPrice = getAmplUSDPrice(ethUSDPrice); - (uint256 targetPrice, bool targetPriceValid) = _getAmpleforthOracleData( - cpiOracle - ); - bool deviationValid = (ethPriceValid && targetPriceValid); - uint256 deviation = (targetPrice > 0) - ? FullMath.mulDiv(marketPrice, ONE, targetPrice) - : type(uint256).max; - deviation = (deviation > MAX_DEVIATION) ? MAX_DEVIATION : deviation; - return (deviation, deviationValid); - } - - //----------------------------------------------------------------------------- - // External Public view methods - - /// @notice Computes active liquidity percentage based on the provided deviation factor. - /// @return The computed active liquidity percentage. - function computeActiveLiqPerc(uint256 deviation) public view returns (uint256) { - return - (deviation <= ONE) - ? _computeActiveLiqPerc(activeLiqPercFn1, deviation) - : _computeActiveLiqPerc(activeLiqPercFn2, deviation); - } - - /// @notice Computes the AMPL price in USD. - /// @param ethUSDPrice The ETH price in USD. - /// @return The computed AMPL price in USD. - function getAmplUSDPrice(uint256 ethUSDPrice) public view returns (uint256) { - return - FullMath.mulDiv( - getWamplUSDPrice(ethUSDPrice), - ONE_AMPL, - WAMPL.wrapperToUnderlying(ONE_WAMPL) // #AMPL per WAMPL - ); - } - - /// @notice Computes the WAMPL price in USD based on ETH price. - /// @param ethUSDPrice The ETH price in USD. - /// @return The computed WAMPL price in USD. - function getWamplUSDPrice(uint256 ethUSDPrice) public view returns (uint256) { - // We first get the WETH-WAMPL price from the pool and then convert that - // to a USD price using the given ETH-USD price. - uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(VAULT.getTwap()); - uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; - // NOTE: Since both weth and wampl have 18 decimals, - // we don't adjust the `wamplPerWeth`. - uint256 wamplPerWeth = FullMath.mulDiv(ONE, ratioX192, (1 << 192)); - return FullMath.mulDiv(ethUSDPrice, ONE, wamplPerWeth); - } - - /// @notice Fetches the current ETH price in USD from the Chainlink oracle. - /// @return The ETH price in USD and its validity. - function getEthUSDPrice() public view returns (uint256, bool) { - return _getCLOracleData(ethOracle); - } - - /// @notice Checks the vault is overweight WAMPL, and looking to sell the extra WAMPL for WETH. - function isOverweightWampl() public view returns (bool) { - // NOTE: This assumes that in the underlying univ3 pool and - // token0 is WETH and token1 is WAMPL. - int24 _marketPrice = VAULT.getTwap(); - int24 _limitLower = VAULT.limitLower(); - int24 _limitUpper = VAULT.limitUpper(); - int24 _limitPrice = (_limitLower + _limitUpper) / 2; - // The limit range has more token1 than token0 if `_marketPrice >= _limitPrice`, - // so the vault looks to sell token1. - return (_marketPrice >= _limitPrice); - } - - /// @return Number of decimals representing 1.0. - function decimals() external pure returns (uint8) { - return uint8(DECIMALS); - } - - //----------------------------------------------------------------------------- - // Private methods - - /// @dev Trims the vault's current liquidity. - /// To be invoked right after a rebalance operation, as it assumes that all of the vault's - /// liquidity has been deployed before trimming. - function _trimLiquidity(uint256 activePerc, bool activeLimitRange) private { - // Calculated baseLiquidityToBurn, baseLiquidityToBurn will be lesser than fullLiquidity, baseLiquidity - // Thus, there's no risk of overflow. - if (activePerc < ONE) { - int24 _fullLower = VAULT.fullLower(); - int24 _fullUpper = VAULT.fullUpper(); - int24 _baseLower = VAULT.baseLower(); - int24 _baseUpper = VAULT.baseUpper(); - (uint128 fullLiquidity, , , , ) = _position(_fullLower, _fullUpper); - (uint128 baseLiquidity, , , , ) = _position(_baseLower, _baseUpper); - uint128 fullLiquidityToBurn = uint128( - FullMath.mulDiv(uint256(fullLiquidity), ONE - activePerc, ONE) - ); - uint128 baseLiquidityToBurn = uint128( - FullMath.mulDiv(uint256(baseLiquidity), ONE - activePerc, ONE) - ); - // docs: https://learn.charm.fi/charm/technical-references/core/alphaprovault#emergencyburn - // We remove the calculated percentage of base and full range liquidity. - VAULT.emergencyBurn(_fullLower, _fullUpper, fullLiquidityToBurn); - VAULT.emergencyBurn(_baseLower, _baseUpper, baseLiquidityToBurn); - } - - // When the limit range is not active, we remove entirely. - if (!activeLimitRange) { - int24 _limitLower = VAULT.limitLower(); - int24 _limitUpper = VAULT.limitUpper(); - (uint128 limitLiquidity, , , , ) = _position(_limitLower, _limitUpper); - // docs: https://learn.charm.fi/charm/technical-references/core/alphaprovault#emergencyburn - VAULT.emergencyBurn(_limitLower, _limitUpper, limitLiquidity); - } - } - - /// @dev Fetches most recent report from the given ampleforth oracle contract. - /// The returned report is a fixed point number with {DECIMALS} places. - function _getAmpleforthOracleData( - IAmpleforthOracle oracle - ) private returns (uint256, bool) { - (uint256 p, bool valid) = oracle.getData(); - return (FullMath.mulDiv(p, ONE, 10 ** oracle.DECIMALS()), valid); - } - - /// @dev A low-level method, which interacts directly with the vault and executes - /// a rebalance even when enough time hasn't elapsed since the last rebalance. - function _execForceRebalance() private { - uint32 _period = VAULT.period(); - VAULT.setPeriod(0); - VAULT.rebalance(); - VAULT.setPeriod(_period); - } - - /// @dev Wrapper around `IUniswapV3Pool.positions()`. - function _position( - int24 tickLower, - int24 tickUpper - ) private view returns (uint128, uint256, uint256, uint128, uint128) { - bytes32 positionKey = PositionKey.compute(address(VAULT), tickLower, tickUpper); - return POOL.positions(positionKey); - } - - /// @dev Fetches most recent report from the given chain link oracle contract. - /// The data is considered invalid if the latest report is stale. - /// The returned report is a fixed point number with {DECIMALS} places. - function _getCLOracleData( - IChainlinkOracle oracle - ) private view returns (uint256, bool) { - (, int256 p, , uint256 updatedAt, ) = oracle.latestRoundData(); - uint256 price = FullMath.mulDiv(uint256(p), ONE, 10 ** oracle.decimals()); - return ( - price, - (block.timestamp - updatedAt) <= CL_ORACLE_STALENESS_THRESHOLD_SEC - ); - } - - /// @dev We compute activeLiqPerc value given a linear fn and deviation. - function _computeActiveLiqPerc( - Line memory fn, - uint256 deviation - ) private pure returns (uint256) { - deviation = (deviation > MAX_DEVIATION) ? MAX_DEVIATION : deviation; - int256 dlY = SafeCast.toInt256(fn.y2) - SafeCast.toInt256(fn.y1); - int256 dlX = SafeCast.toInt256(fn.x2) - SafeCast.toInt256(fn.x1); - int256 activeLiqPerc = SafeCast.toInt256(fn.y2) + - (((SafeCast.toInt256(deviation) - SafeCast.toInt256(fn.x2)) * dlY) / dlX); - activeLiqPerc = (activeLiqPerc < int256(MIN_ACTIVE_LIQ_PERC)) - ? int256(MIN_ACTIVE_LIQ_PERC) - : activeLiqPerc; - activeLiqPerc = (activeLiqPerc > int256(ONE)) ? int256(ONE) : activeLiqPerc; - // Casting from int256 to uint256 here is safe as activeLiqPerc >= 0. - return uint256(activeLiqPerc); - } -} diff --git a/spot-vaults/contracts/_interfaces/IMetaOracle.sol b/spot-vaults/contracts/_interfaces/IMetaOracle.sol new file mode 100644 index 00000000..b705bbda --- /dev/null +++ b/spot-vaults/contracts/_interfaces/IMetaOracle.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BUSL-1.1 + +/// @notice Oracle adapter for AMPL and its family of assets. +// solhint-disable-next-line compiler-version +interface IMetaOracle { + /// @return Number of decimals representing the prices returned. + function decimals() external pure returns (uint8); + + /// @return price The price of USDC tokens in dollars. + /// @return isValid True if the returned price is valid. + function usdcPrice() external returns (uint256 price, bool isValid); + + /// @notice Computes SPOT's market price over FMV price. + /// @return deviation The computed deviation factor. + /// @return isValid True if the returned deviation is valid. + function spotPriceDeviation() external returns (uint256 deviation, bool isValid); + + /// @notice Computes AMPL's market price over price target. + /// @return deviation The computed deviation factor. + /// @return isValid True if the returned deviation is valid. + function amplPriceDeviation() external returns (uint256 deviation, bool isValid); + + /// @return price The price of SPOT in dollars. + /// @return isValid True if the returned price is valid. + function spotUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The price of AMPL in dollars. + /// @return isValid True if the returned price is valid. + function amplUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The SPOT FMV price in dollars. + /// @return isValid True if the returned price is valid. + function spotFmvUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The AMPL target price in dollars. + /// @return isValid True if the returned price is valid. + function amplTargetUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The WAMPL price in dollars. + /// @return isValid True if the returned price is valid. + function wamplUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The ETH price in dollars. + /// @return isValid True if the returned price is valid. + function ethUsdPrice() external returns (uint256 price, bool isValid); +} diff --git a/spot-vaults/contracts/_interfaces/IPerpPricer.sol b/spot-vaults/contracts/_interfaces/IPerpPricer.sol new file mode 100644 index 00000000..a98ef938 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/IPerpPricer.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 + +/// @notice Oracle contract to price perps and its underlying token. +// solhint-disable-next-line compiler-version +interface IPerpPricer { + /// @return Number of decimals representing the prices returned. + function decimals() external pure returns (uint8); + + /// @return price The price of reference USD tokens. + /// @return isValid True if the returned price is valid. + function usdPrice() external returns (uint256 price, bool isValid); + + /// @return price The price of perp tokens in dollars. + /// @return isValid True if the returned price is valid. + function perpUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price The price of underlying tokens (which back perp) in dollars. + /// @return isValid True if the returned price is valid. + function underlyingUsdPrice() external returns (uint256 price, bool isValid); + + /// @return price Perp's fmv price in dollars. + /// @return isValid True if the returned price is valid. + function perpFmvUsdPrice() external returns (uint256 price, bool isValid); +} diff --git a/spot-vaults/contracts/_interfaces/ISpotPricingStrategy.sol b/spot-vaults/contracts/_interfaces/ISpotPricingStrategy.sol deleted file mode 100644 index 2f794c76..00000000 --- a/spot-vaults/contracts/_interfaces/ISpotPricingStrategy.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -/** - * @title ISpotPricingStrategy - * - * @notice Pricing strategy adapter for a BillBroker vault - * which accepts Perp and USDC tokens. - * - */ -// solhint-disable-next-line compiler-version -interface ISpotPricingStrategy { - /// @return Number of decimals representing the prices returned. - function decimals() external pure returns (uint8); - - /// @return price The price of USD tokens. - /// @return isValid True if the returned price is valid. - function usdPrice() external returns (uint256 price, bool isValid); - - /// @return price The price of perp tokens. - /// @return isValid True if the returned price is valid. - function perpPrice() external returns (uint256 price, bool isValid); -} diff --git a/spot-vaults/contracts/_interfaces/errors/BillBrokerErrors.sol b/spot-vaults/contracts/_interfaces/errors/BillBrokerErrors.sol new file mode 100644 index 00000000..e1dc341f --- /dev/null +++ b/spot-vaults/contracts/_interfaces/errors/BillBrokerErrors.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +/// @notice Expect AR lower bound to be under the upper bound. +error InvalidARBound(); + +/// @notice Expected pre and post swap AR delta to be non-increasing or non-decreasing. +error UnexpectedARDelta(); diff --git a/spot-vaults/contracts/_interfaces/BillBrokerErrors.sol b/spot-vaults/contracts/_interfaces/errors/CommonErrors.sol similarity index 63% rename from spot-vaults/contracts/_interfaces/BillBrokerErrors.sol rename to spot-vaults/contracts/_interfaces/errors/CommonErrors.sol index babbae79..42e6d9b0 100644 --- a/spot-vaults/contracts/_interfaces/BillBrokerErrors.sol +++ b/spot-vaults/contracts/_interfaces/errors/CommonErrors.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +/// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; /// @notice Expected contract call to be triggered by authorized caller. @@ -10,15 +10,6 @@ error UnexpectedDecimals(); /// @notice Expected perc value to be at most (1 * 10**DECIMALS), i.e) 1.0 or 100%. error InvalidPerc(); -/// @notice Expected Senior CDR bound to be more than 1.0 or 100%. -error InvalidSeniorCDRBound(); - -/// @notice Expect AR lower bound to be under the upper bound. -error InvalidARBound(); - -/// @notice Expected pre and post swap AR delta to be non-increasing or non-decreasing. -error UnexpectedARDelta(); - /// @notice Slippage higher than tolerance requested by user. error SlippageTooHigh(); @@ -27,3 +18,9 @@ error UnacceptableSwap(); /// @notice Expected usable external price. error UnreliablePrice(); + +/// @notice Range upper is larger than lower +error InvalidRange(); + +/// @notice Expected range delta to be smaller. +error UnexpectedRangeDelta(); diff --git a/spot-vaults/contracts/_interfaces/external/IAMPL.sol b/spot-vaults/contracts/_interfaces/external/IAMPL.sol index 4fb916eb..63d84404 100644 --- a/spot-vaults/contracts/_interfaces/external/IAMPL.sol +++ b/spot-vaults/contracts/_interfaces/external/IAMPL.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity ^0.8.24; - -import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; +// solhint-disable-next-line compiler-version import { IAmpleforth } from "./IAmpleforth.sol"; - -interface IAMPL is IERC20Upgradeable { +interface IAMPL { function monetaryPolicy() external view returns (IAmpleforth); } diff --git a/spot-vaults/contracts/_interfaces/external/IAlphaProVault.sol b/spot-vaults/contracts/_interfaces/external/IAlphaProVault.sol index d599cdfd..39b4d5fe 100644 --- a/spot-vaults/contracts/_interfaces/external/IAlphaProVault.sol +++ b/spot-vaults/contracts/_interfaces/external/IAlphaProVault.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -// solhint-disable-next-line compiler-version -pragma solidity ^0.7.6; +pragma solidity ^0.8.24; import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; diff --git a/spot-vaults/contracts/_interfaces/external/IAmpleforth.sol b/spot-vaults/contracts/_interfaces/external/IAmpleforth.sol index 9cae4b77..43b8f607 100644 --- a/spot-vaults/contracts/_interfaces/external/IAmpleforth.sol +++ b/spot-vaults/contracts/_interfaces/external/IAmpleforth.sol @@ -1,8 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity ^0.8.24; - -import { IAmpleforthOracle } from "./IAmpleforthOracle.sol"; - +// solhint-disable-next-line compiler-version interface IAmpleforth { - function cpiOracle() external view returns (IAmpleforthOracle); + function getTargetRate() external returns (uint256, bool); } diff --git a/spot-vaults/contracts/_interfaces/external/IBondController.sol b/spot-vaults/contracts/_interfaces/external/IBondController.sol new file mode 100644 index 00000000..5488c920 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/external/IBondController.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +interface IBondController { + function collateralBalance() external view returns (uint256); +} diff --git a/spot-vaults/contracts/_interfaces/external/IERC20.sol b/spot-vaults/contracts/_interfaces/external/IERC20.sol new file mode 100644 index 00000000..caab7e44 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/external/IERC20.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +interface IERC20 { + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function transferFrom( + address from, + address to, + uint256 value + ) external returns (bool); +} diff --git a/spot-vaults/contracts/_interfaces/external/IPerpFeePolicy.sol b/spot-vaults/contracts/_interfaces/external/IPerpFeePolicy.sol new file mode 100644 index 00000000..b4aba5c9 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/external/IPerpFeePolicy.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +interface IPerpFeePolicy { + function decimals() external returns (uint8); + function deviationRatio() external returns (uint256); + function computePerpRolloverFeePerc(uint256 dr) external returns (int256); +} diff --git a/spot-vaults/contracts/_interfaces/external/IPerpetualTranche.sol b/spot-vaults/contracts/_interfaces/external/IPerpetualTranche.sol new file mode 100644 index 00000000..a730f331 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/external/IPerpetualTranche.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +interface IPerpetualTranche { + function underlying() external view returns (address); + function getTVL() external returns (uint256); + function totalSupply() external returns (uint256); + function getReserveCount() external returns (uint256); + function getReserveAt(uint256 index) external returns (address); + function deviationRatio() external returns (uint256); + function getReserveTokenValue(address t) external returns (uint256); + function getReserveTokenBalance(address t) external returns (uint256); + function feePolicy() external returns (address); +} diff --git a/spot-vaults/contracts/_interfaces/external/ITranche.sol b/spot-vaults/contracts/_interfaces/external/ITranche.sol new file mode 100644 index 00000000..51a582d3 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/external/ITranche.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +interface ITranche { + function bond() external view returns (address); + function totalSupply() external view returns (uint256); +} diff --git a/spot-vaults/contracts/_interfaces/external/IWAMPL.sol b/spot-vaults/contracts/_interfaces/external/IWAMPL.sol index 0176dd22..b5f24a1a 100644 --- a/spot-vaults/contracts/_interfaces/external/IWAMPL.sol +++ b/spot-vaults/contracts/_interfaces/external/IWAMPL.sol @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable-next-line compiler-version -pragma solidity ^0.7.6; - interface IWAMPL { function wrapperToUnderlying(uint256 wamples) external view returns (uint256); } diff --git a/spot-vaults/contracts/_interfaces/BillBrokerTypes.sol b/spot-vaults/contracts/_interfaces/types/BillBrokerTypes.sol similarity index 55% rename from spot-vaults/contracts/_interfaces/BillBrokerTypes.sol rename to spot-vaults/contracts/_interfaces/types/BillBrokerTypes.sol index d24601ad..6b61fcb7 100644 --- a/spot-vaults/contracts/_interfaces/BillBrokerTypes.sol +++ b/spot-vaults/contracts/_interfaces/types/BillBrokerTypes.sol @@ -1,25 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; -/// @notice A data structure to define a geometric Line with two points. -struct Line { - /// @notice x-coordinate of the first point. - uint256 x1; - /// @notice y-coordinate of the first point. - uint256 y1; - /// @notice x-coordinate of the second point. - uint256 x2; - /// @notice y-coordinate of the second point. - uint256 y2; -} - -/// @notice A data structure to define a numeric Range. -struct Range { - /// @notice Lower bound of the range. - uint256 lower; - /// @notice Upper bound of the range. - uint256 upper; -} +import { Range } from "./CommonTypes.sol"; /// @notice A data structure to store various fees associated with BillBroker operations. struct BillBrokerFees { @@ -27,10 +9,11 @@ struct BillBrokerFees { uint256 mintFeePerc; /// @notice The percentage fee charged for burning BillBroker LP tokens. uint256 burnFeePerc; - /// @notice Range of fee percentages for swapping from perp tokens to USD. - Range perpToUSDSwapFeePercs; - /// @notice Range of fee percentages for swapping from USD to perp tokens. - Range usdToPerpSwapFeePercs; + /// @notice Range of fee factors for swapping from perp tokens to USD. + /// @dev Factor of 1.02 implies a +2% fees, and 0.98 implies a -2% fees. + Range perpToUSDSwapFeeFactors; + /// @notice Range of fee factors for swapping from USD to perp tokens. + Range usdToPerpSwapFeeFactors; /// @notice The percentage of the swap fees that goes to the protocol. uint256 protocolSwapSharePerc; } diff --git a/spot-vaults/contracts/_interfaces/types/CommonTypes.sol b/spot-vaults/contracts/_interfaces/types/CommonTypes.sol new file mode 100644 index 00000000..00ea2009 --- /dev/null +++ b/spot-vaults/contracts/_interfaces/types/CommonTypes.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +/// @notice A data structure to define a geometric Line with two points. +struct Line { + // @dev x-coordinate of the first point. + uint256 x1; + // @dev y-coordinate of the first point. + uint256 y1; + // @dev x-coordinate of the second point. + uint256 x2; + // @dev y-coordinate of the second point. + uint256 y2; +} + +/// @notice A data structure to define a numeric Range. +struct Range { + // @dev Lower bound of the range. + uint256 lower; + // @dev Upper bound of the range. + uint256 upper; +} diff --git a/spot-vaults/contracts/_strategies/SpotAppraiser.sol b/spot-vaults/contracts/_strategies/SpotAppraiser.sol deleted file mode 100644 index 05cd2b28..00000000 --- a/spot-vaults/contracts/_strategies/SpotAppraiser.sol +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.24; - -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ITranche } from "@ampleforthorg/spot-contracts/contracts/_interfaces/buttonwood/ITranche.sol"; -import { IBondController } from "@ampleforthorg/spot-contracts/contracts/_interfaces/buttonwood/IBondController.sol"; -import { IPerpetualTranche } from "@ampleforthorg/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol"; -import { IChainlinkOracle } from "../_interfaces/external/IChainlinkOracle.sol"; -import { IAmpleforthOracle } from "../_interfaces/external/IAmpleforthOracle.sol"; -import { ISpotPricingStrategy } from "../_interfaces/ISpotPricingStrategy.sol"; -import { InvalidSeniorCDRBound } from "../_interfaces/BillBrokerErrors.sol"; - -/** - * @title SpotAppraiser - * - * @notice Pricing strategy adapter for a BillBroker vault which accepts - * SPOT (as the perp token) and dollar tokens like USDC. - * - * AMPL is the underlying token for SPOT. - * The market price of AMPL is mean reverting and eventually converges to its target. - * However, it can significantly deviate from the target in the near term. - * - * SPOT is a perpetual claim on AMPL senior tranches. Insofar as SPOT is fully backed by - * healthy senior tranches, we can price spot reliably using the following strategy: - * - * SPOT_PRICE = MULTIPLIER * AMPL_TARGET - * MULTIPLIER = spot.getTVL() / spot.totalSupply(), which is it's enrichment/debasement factor. - * To know more, read the spot documentation. - * - * We get the AMPL target price from Ampleforth's CPI oracle, - * which is also used by the protocol to adjust AMPL supply through rebasing. - * - * And the MULTIPLIER is directly queried from the SPOT contract. - * - */ -contract SpotAppraiser is Ownable, ISpotPricingStrategy { - //------------------------------------------------------------------------- - // Libraries - using Math for uint256; - - //------------------------------------------------------------------------- - // Constants & Immutables - - uint256 private constant DECIMALS = 18; - uint256 private constant ONE = (10 ** DECIMALS); - uint256 private constant SPOT_DR_DECIMALS = 8; - uint256 private constant SPOT_DR_ONE = (10 ** SPOT_DR_DECIMALS); - uint256 public constant CL_ORACLE_DECIMALS = 8; - uint256 public constant CL_ORACLE_STALENESS_THRESHOLD_SEC = 3600 * 48; // 2 days - uint256 public constant USD_UPPER_BOUND = (101 * ONE) / 100; // 1.01$ - uint256 public constant USD_LOWER_BOUND = (99 * ONE) / 100; // 0.99$ - uint256 public constant AMPL_DUST_AMT = 25000 * (10 ** 9); // 25000 AMPL - - /// @notice Address of the SPOT (perpetual tranche) ERC-20 token contract. - IPerpetualTranche public immutable SPOT; - - /// @notice Address of the AMPL ERC-20 token contract. - IERC20 public immutable AMPL; - - /// @notice Address of the USD token market price oracle. - IChainlinkOracle public immutable USD_ORACLE; - - /// @notice Number of decimals representing the prices returned by the chainlink oracle. - uint256 public immutable USD_ORACLE_DECIMALS; - - /// @notice Address of the Ampleforth CPI oracle. (provides the inflation-adjusted target price for AMPL). - IAmpleforthOracle public immutable AMPL_CPI_ORACLE; - - /// @notice Number of decimals representing the prices returned by the ampleforth oracle. - uint256 public immutable AMPL_CPI_ORACLE_DECIMALS; - - //------------------------------------------------------------------------- - // Storage - - /// @notice The minimum "deviation ratio" of the SPOT outside which it's considered unhealthy. - uint256 public minSPOTDR; - - /// @notice The minimum CDR of senior tranches backing SPOT outside which it's considered unhealthy. - uint256 public minSeniorCDR; - - //----------------------------------------------------------------------------- - // Constructor - - /// @notice Contract constructor. - /// @param spot Address of the SPOT token. - /// @param usdOracle Address of the USD token market price oracle token. - /// @param cpiOracle Address of the Ampleforth CPI oracle. - constructor( - IPerpetualTranche spot, - IChainlinkOracle usdOracle, - IAmpleforthOracle cpiOracle - ) Ownable() { - SPOT = spot; - AMPL = IERC20(address(spot.underlying())); - - USD_ORACLE = usdOracle; - USD_ORACLE_DECIMALS = usdOracle.decimals(); - - AMPL_CPI_ORACLE = cpiOracle; - AMPL_CPI_ORACLE_DECIMALS = cpiOracle.DECIMALS(); - - minSPOTDR = (ONE * 8) / 10; // 0.8 - minSeniorCDR = (ONE * 11) / 10; // 110% - } - - //-------------------------------------------------------------------------- - // Owner only methods - - /// @notice Controls the minimum `deviationRatio` ratio of SPOT below which SPOT is considered unhealthy. - /// @param minSPOTDR_ The minimum SPOT `deviationRatio`. - function updateMinSPOTDR(uint256 minSPOTDR_) external onlyOwner { - minSPOTDR = minSPOTDR_; - } - - /// @notice Controls the minimum CDR of SPOT's senior tranche below which SPOT is considered unhealthy. - /// @param minSeniorCDR_ The minimum senior tranche CDR. - function updateMinPerpCollateralCDR(uint256 minSeniorCDR_) external onlyOwner { - if (minSeniorCDR_ < ONE) { - revert InvalidSeniorCDRBound(); - } - minSeniorCDR = minSeniorCDR_; - } - - //-------------------------------------------------------------------------- - // External methods - - /// @return p The price of the usd token in dollars. - /// @return v True if the price is valid and can be used by downstream consumers. - function usdPrice() external view override returns (uint256, bool) { - (uint256 p, bool v) = _getCLOracleData(USD_ORACLE, USD_ORACLE_DECIMALS); - // If the market price of the USD coin deviated too much from 1$, - // it's an indication of some systemic issue with the USD token - // and thus its price should be considered unreliable. - return (ONE, (v && p < USD_UPPER_BOUND && p > USD_LOWER_BOUND)); - } - - /// @return p The price of the spot token in dollar coins. - /// @return v True if the price is valid and can be used by downstream consumers. - function perpPrice() external override returns (uint256, bool) { - // NOTE: Since {DECIMALS} == {AMPL_CPI_ORACLE_DECIMALS} == 18 - // we don't adjust the returned values. - (uint256 targetPrice, bool targetPriceValid) = AMPL_CPI_ORACLE.getData(); - uint256 p = targetPrice.mulDiv(SPOT.getTVL(), SPOT.totalSupply()); - bool v = (targetPriceValid && isSPOTHealthy()); - return (p, v); - } - - /// @return Number of decimals representing a price of 1.0 USD. - function decimals() external pure override returns (uint8) { - return uint8(DECIMALS); - } - - //----------------------------------------------------------------------------- - // Public methods - - /// @return If the spot token is healthy. - function isSPOTHealthy() public returns (bool) { - // If the SPOT's `deviationRatio` is lower than the defined bound - // i.e) it doesn't have enough capital to cover future rollovers, - // we consider it unhealthy. - uint256 spotDR = SPOT.deviationRatio().mulDiv(ONE, SPOT_DR_ONE); - if (spotDR < minSPOTDR) { - return false; - } - - // We compute the CDR of all the senior tranches backing perp. - // If any one of the seniors is mature or has a CDR below below the defined minimum, - // we consider it unhealthy. - // NOTE: Any CDR below 100%, means that the tranche is impaired - // and is roughly equivalent to holding AMPL. - uint8 reserveCount = uint8(SPOT.getReserveCount()); - for (uint8 i = 1; i < reserveCount; i++) { - ITranche tranche = ITranche(address(SPOT.getReserveAt(i))); - IBondController bond = IBondController(tranche.bond()); - if (bond.isMature()) { - return false; - } - uint256 seniorCDR = AMPL.balanceOf(address(bond)).mulDiv( - ONE, - tranche.totalSupply() - ); - if (seniorCDR < minSeniorCDR) { - return false; - } - } - - // If SPOT has ANY raw AMPL as collateral, we consider it unhealthy. - // NOTE: In practice some dust might exist or someone could grief this check - // by transferring some dust AMPL into the spot contract. - // We consider SPOT unhealthy if it has more than `AMPL_DUST_AMT` AMPL. - if (AMPL.balanceOf(address(SPOT)) > AMPL_DUST_AMT) { - return false; - } - - return true; - } - - //----------------------------------------------------------------------------- - // Private methods - - /// @dev Fetches most recent report from the given chain link oracle contract. - /// The data is considered invalid if the latest report is stale. - function _getCLOracleData( - IChainlinkOracle oracle, - uint256 oracleDecimals - ) private view returns (uint256, bool) { - (, int256 p, , uint256 updatedAt, ) = oracle.latestRoundData(); - uint256 price = uint256(p).mulDiv(ONE, 10 ** oracleDecimals); - return ( - price, - (block.timestamp - updatedAt) <= CL_ORACLE_STALENESS_THRESHOLD_SEC - ); - } -} diff --git a/spot-vaults/contracts/_strategies/SpotCDRPricer.sol b/spot-vaults/contracts/_strategies/SpotCDRPricer.sol deleted file mode 100644 index 2848949d..00000000 --- a/spot-vaults/contracts/_strategies/SpotCDRPricer.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.24; - -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { IPerpetualTranche } from "@ampleforthorg/spot-contracts/contracts/_interfaces/IPerpetualTranche.sol"; -import { IChainlinkOracle } from "../_interfaces/external/IChainlinkOracle.sol"; -import { IAmpleforthOracle } from "../_interfaces/external/IAmpleforthOracle.sol"; -import { ISpotPricingStrategy } from "../_interfaces/ISpotPricingStrategy.sol"; - -/** - * @title SpotCDRPricer - * - * @notice Pricing strategy adapter for SPOT. - * - * SPOT is a perpetual claim on AMPL senior tranches. - * We price spot based on the redeemable value of it's collateral at maturity. - * NOTE: SPOT's internal `getTVL` prices the collateral this way. - * - * SPOT_PRICE = (spot.getTVL() / spot.totalSupply()) * AMPL_TARGET - * - * We get the AMPL target price from Ampleforth's CPI oracle, - * which is also used by the protocol to adjust AMPL supply through rebasing. - * - */ -contract SpotCDRPricer is ISpotPricingStrategy { - //------------------------------------------------------------------------- - // Libraries - using Math for uint256; - - //------------------------------------------------------------------------- - // Constants & Immutables - - uint256 private constant DECIMALS = 18; - uint256 private constant ONE = (10 ** DECIMALS); - uint256 public constant CL_ORACLE_DECIMALS = 8; - uint256 public constant CL_ORACLE_STALENESS_THRESHOLD_SEC = 3600 * 48; // 2 days - uint256 public constant USD_UPPER_BOUND = (101 * ONE) / 100; // 1.01$ - uint256 public constant USD_LOWER_BOUND = (99 * ONE) / 100; // 0.99$ - - /// @notice Address of the SPOT (perpetual tranche) ERC-20 token contract. - IPerpetualTranche public immutable SPOT; - - /// @notice Address of the AMPL ERC-20 token contract. - IERC20 public immutable AMPL; - - /// @notice Address of the USD token market price oracle. - IChainlinkOracle public immutable USD_ORACLE; - - /// @notice Number of decimals representing the prices returned by the chainlink oracle. - uint256 public immutable USD_ORACLE_DECIMALS; - - /// @notice Address of the Ampleforth CPI oracle. (provides the inflation-adjusted target price for AMPL). - IAmpleforthOracle public immutable AMPL_CPI_ORACLE; - - /// @notice Number of decimals representing the prices returned by the ampleforth oracle. - uint256 public immutable AMPL_CPI_ORACLE_DECIMALS; - - //----------------------------------------------------------------------------- - // Constructor - - /// @notice Contract constructor. - /// @param spot Address of the SPOT token. - /// @param usdOracle Address of the USD token market price oracle token. - /// @param cpiOracle Address of the Ampleforth CPI oracle. - constructor( - IPerpetualTranche spot, - IChainlinkOracle usdOracle, - IAmpleforthOracle cpiOracle - ) { - SPOT = spot; - AMPL = IERC20(address(spot.underlying())); - - USD_ORACLE = usdOracle; - USD_ORACLE_DECIMALS = usdOracle.decimals(); - - AMPL_CPI_ORACLE = cpiOracle; - AMPL_CPI_ORACLE_DECIMALS = cpiOracle.DECIMALS(); - } - - //-------------------------------------------------------------------------- - // External methods - - /// @return p The price of the usd token in dollars. - /// @return v True if the price is valid and can be used by downstream consumers. - function usdPrice() external view override returns (uint256, bool) { - (uint256 p, bool v) = _getCLOracleData(USD_ORACLE, USD_ORACLE_DECIMALS); - // If the market price of the USD coin deviated too much from 1$, - // it's an indication of some systemic issue with the USD token - // and thus its price should be considered unreliable. - return (ONE, (v && p < USD_UPPER_BOUND && p > USD_LOWER_BOUND)); - } - - /// @return p The price of the spot token in dollar coins. - /// @return v True if the price is valid and can be used by downstream consumers. - function perpPrice() external override returns (uint256, bool) { - // NOTE: Since {DECIMALS} == {AMPL_CPI_ORACLE_DECIMALS} == 18 - // we don't adjust the returned values. - (uint256 targetPrice, bool targetPriceValid) = AMPL_CPI_ORACLE.getData(); - uint256 p = targetPrice.mulDiv(SPOT.getTVL(), SPOT.totalSupply()); - return (p, targetPriceValid); - } - - /// @return Number of decimals representing a price of 1.0 USD. - function decimals() external pure override returns (uint8) { - return uint8(DECIMALS); - } - - //----------------------------------------------------------------------------- - // Private methods - - /// @dev Fetches most recent report from the given chain link oracle contract. - /// The data is considered invalid if the latest report is stale. - function _getCLOracleData( - IChainlinkOracle oracle, - uint256 oracleDecimals - ) private view returns (uint256, bool) { - (, int256 p, , uint256 updatedAt, ) = oracle.latestRoundData(); - uint256 price = uint256(p).mulDiv(ONE, 10 ** oracleDecimals); - return ( - price, - (block.timestamp - updatedAt) <= CL_ORACLE_STALENESS_THRESHOLD_SEC - ); - } -} diff --git a/spot-vaults/contracts/_strategies/SpotPricer.sol b/spot-vaults/contracts/_strategies/SpotPricer.sol new file mode 100644 index 00000000..b96ee9d0 --- /dev/null +++ b/spot-vaults/contracts/_strategies/SpotPricer.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BUSL-1.1 +// solhint-disable-next-line compiler-version +pragma solidity ^0.7.6; +pragma abicoder v2; + +import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; +import { UniswapV3PoolHelpers } from "../_utils/UniswapV3PoolHelpers.sol"; + +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; +import { IERC20 } from "../_interfaces/external/IERC20.sol"; +import { IWAMPL } from "../_interfaces/external/IWAMPL.sol"; +import { IPerpetualTranche } from "../_interfaces/external/IPerpetualTranche.sol"; +import { IChainlinkOracle } from "../_interfaces/external/IChainlinkOracle.sol"; +import { IAMPL } from "../_interfaces/external/IAMPL.sol"; +import { IAmpleforth } from "../_interfaces/external/IAmpleforth.sol"; + +import { IPerpPricer } from "../_interfaces/IPerpPricer.sol"; +import { IMetaOracle } from "../_interfaces/IMetaOracle.sol"; + +/** + * @title SpotPricer + * + * @notice A pricing oracle for SPOT, a perpetual claim on AMPL senior tranches. + * + * Internally aggregates prices from multiple oracles. + * Chainlink for USDC and ETH prices, + * The Ampleforth monetary policy for the AMPL price target and + * UniV3 pools for current AMPL and SPOT market prices. + * + */ +contract SpotPricer is IPerpPricer, IMetaOracle { + using FullMath for uint256; + + //------------------------------------------------------------------------- + // Constants + + /// @dev Standardizes prices from various oracles and returns the final value + /// as a fixed point number with {DECIMALS} places. + uint256 private constant DECIMALS = 18; + uint256 private constant ONE = (10 ** DECIMALS); + + /// @dev We bound the deviation factor to 100.0. + uint256 public constant MAX_DEVIATION = 100 * ONE; // 100.0 + + /// @dev Token denominations. + uint256 private constant ONE_USDC = 1e6; + uint256 private constant ONE_WETH = 1e18; + uint256 private constant ONE_SPOT = 1e9; + uint256 private constant ONE_AMPL = 1e9; + uint256 private constant ONE_WAMPL = 1e18; + + /// @dev Oracle constants. + uint256 private constant CL_ETH_ORACLE_STALENESS_THRESHOLD_SEC = 3600 * 12; // 12 hours + uint256 private constant CL_USDC_ORACLE_STALENESS_THRESHOLD_SEC = 3600 * 48; // 2 day + uint256 private constant USDC_UPPER_BOUND = (101 * ONE) / 100; // 1.01$ + uint256 private constant USDC_LOWER_BOUND = (99 * ONE) / 100; // 0.99$ + uint32 private constant TWAP_DURATION = 3600; + + //------------------------------------------------------------------------- + // Storage + + /// @notice Address of the WETH-WAMPL univ3 pool. + IUniswapV3Pool public immutable WETH_WAMPL_POOL; + + /// @notice Address of the USDC-SPOT univ3 pool. + IUniswapV3Pool public immutable USDC_SPOT_POOL; + + /// @notice Address of the ETH token market price oracle. + IChainlinkOracle public immutable ETH_ORACLE; + + /// @notice Address of the USD token market price oracle. + IChainlinkOracle public immutable USDC_ORACLE; + + /// @notice Address of the Ampleforth monetary policy. + /// (provides the inflation-adjusted target price for AMPL) + IAmpleforth public immutable AMPLEFORTH_POLICY; + + /// @notice Address of the WAMPL ERC-20 token contract. + IWAMPL public immutable WAMPL; + + /// @notice Address of the USDC ERC-20 token contract. + IERC20 public immutable USDC; + + /// @notice Address of the SPOT (perpetual tranche) ERC-20 token contract. + IPerpetualTranche public immutable SPOT; + + /// @notice Address of the AMPL ERC-20 token contract. + IERC20 public immutable AMPL; + + //----------------------------------------------------------------------------- + // Constructor + + /// @notice Contract constructor. + /// @param wethWamplPool Address of the WETH-WAMPL univ3 pool. + /// @param usdcSpotPool Address of the USDC-SPOT univ3 pool. + /// @param ethOracle Address of the ETH market price oracle. + /// @param usdcOracle Address of the USD coin market price oracle. + constructor( + IUniswapV3Pool wethWamplPool, + IUniswapV3Pool usdcSpotPool, + IChainlinkOracle ethOracle, + IChainlinkOracle usdcOracle + ) { + WETH_WAMPL_POOL = wethWamplPool; + USDC_SPOT_POOL = usdcSpotPool; + + ETH_ORACLE = ethOracle; + USDC_ORACLE = usdcOracle; + + WAMPL = IWAMPL(wethWamplPool.token1()); + USDC = IERC20(usdcSpotPool.token0()); + + IPerpetualTranche spot = IPerpetualTranche(usdcSpotPool.token1()); + SPOT = spot; + address ampl = spot.underlying(); + AMPL = IERC20(ampl); + + AMPLEFORTH_POLICY = IAmpleforth(IAMPL(ampl).monetaryPolicy()); + } + + //-------------------------------------------------------------------------- + // IPerpPricer methods + + /// @inheritdoc IPerpPricer + function decimals() external pure override(IPerpPricer, IMetaOracle) returns (uint8) { + return uint8(DECIMALS); + } + + /// @inheritdoc IPerpPricer + function usdPrice() external view override returns (uint256, bool) { + return usdcPrice(); + } + + /// @inheritdoc IPerpPricer + function perpUsdPrice() external view override returns (uint256, bool) { + return spotUsdPrice(); + } + + /// @inheritdoc IPerpPricer + function underlyingUsdPrice() external view override returns (uint256, bool) { + return amplUsdPrice(); + } + + /// @inheritdoc IPerpPricer + function perpFmvUsdPrice() external override returns (uint256, bool) { + return spotFmvUsdPrice(); + } + + //-------------------------------------------------------------------------- + // IMetaOracle methods + + /// @inheritdoc IMetaOracle + function usdcPrice() public view override returns (uint256, bool) { + (uint256 p, bool v) = _getCLOracleData( + USDC_ORACLE, + CL_USDC_ORACLE_STALENESS_THRESHOLD_SEC + ); + // If the market price of the USD coin deviated too much from 1$, + // it's an indication of some systemic issue with the USD token + // and thus its price should be considered unreliable. + return (ONE, (v && p < USDC_UPPER_BOUND && p > USDC_LOWER_BOUND)); + } + + /// @inheritdoc IMetaOracle + function spotPriceDeviation() public override returns (uint256, bool) { + (uint256 marketPrice, bool marketPriceValid) = spotUsdPrice(); + (uint256 targetPrice, bool targetPriceValid) = spotFmvUsdPrice(); + uint256 deviation = (targetPrice > 0) + ? marketPrice.mulDiv(ONE, targetPrice) + : type(uint256).max; + if (deviation > MAX_DEVIATION) { + deviation = MAX_DEVIATION; + } + return (deviation, (marketPriceValid && targetPriceValid)); + } + + /// @inheritdoc IMetaOracle + function amplPriceDeviation() public override returns (uint256, bool) { + (uint256 marketPrice, bool marketPriceValid) = amplUsdPrice(); + (uint256 targetPrice, bool targetPriceValid) = amplTargetUsdPrice(); + uint256 deviation = (targetPrice > 0) + ? marketPrice.mulDiv(ONE, targetPrice) + : type(uint256).max; + if (deviation > MAX_DEVIATION) { + deviation = MAX_DEVIATION; + } + return (deviation, (marketPriceValid && targetPriceValid)); + } + + /// @inheritdoc IMetaOracle + function spotUsdPrice() public view override returns (uint256, bool) { + uint256 usdcPerSpot = UniswapV3PoolHelpers.calculateTwap( + UniswapV3PoolHelpers.getTwapTick(USDC_SPOT_POOL, TWAP_DURATION), + ONE_USDC, + ONE_SPOT, + ONE + ); + (, bool usdcPriceValid) = usdcPrice(); + return (usdcPerSpot, usdcPriceValid); + } + + /// @inheritdoc IMetaOracle + function amplUsdPrice() public view override returns (uint256, bool) { + (uint256 wamplPrice, bool wamplPriceValid) = wamplUsdPrice(); + uint256 amplPrice = wamplPrice.mulDiv( + ONE_AMPL, + WAMPL.wrapperToUnderlying(ONE_WAMPL) + ); + return (amplPrice, wamplPriceValid); + } + + /// @inheritdoc IMetaOracle + function spotFmvUsdPrice() public override returns (uint256, bool) { + (uint256 targetPrice, bool targetPriceValid) = amplTargetUsdPrice(); + return (targetPrice.mulDiv(SPOT.getTVL(), SPOT.totalSupply()), targetPriceValid); + } + + /// @inheritdoc IMetaOracle + function amplTargetUsdPrice() public override returns (uint256, bool) { + // NOTE: Since {DECIMALS} == {AMPLEFORTH_POLICY_DECIMALS} == 18 + // we don't adjust the returned values. + return AMPLEFORTH_POLICY.getTargetRate(); + } + + /// @inheritdoc IMetaOracle + function wamplUsdPrice() public view override returns (uint256, bool) { + uint256 wethPerWampl = UniswapV3PoolHelpers.calculateTwap( + UniswapV3PoolHelpers.getTwapTick(WETH_WAMPL_POOL, TWAP_DURATION), + ONE_WETH, + ONE_WAMPL, + ONE + ); + (uint256 ethPrice, bool ethPriceValid) = ethUsdPrice(); + uint256 wamplPrice = ethPrice.mulDiv(wethPerWampl, ONE); + return (wamplPrice, ethPriceValid); + } + + /// @inheritdoc IMetaOracle + function ethUsdPrice() public view override returns (uint256, bool) { + return _getCLOracleData(ETH_ORACLE, CL_ETH_ORACLE_STALENESS_THRESHOLD_SEC); + } + + //-------------------------------------------------------------------------- + // Private methods + + /// @dev Fetches price from a given Chainlink oracle. + function _getCLOracleData( + IChainlinkOracle oracle, + uint256 stalenessThresholdSec + ) private view returns (uint256, bool) { + (, int256 p, , uint256 updatedAt, ) = oracle.latestRoundData(); + uint256 price = uint256(p).mulDiv(ONE, 10 ** oracle.decimals()); + return (price, (block.timestamp - updatedAt) <= stalenessThresholdSec); + } +} diff --git a/spot-vaults/contracts/_test/LineHelpersTester.sol b/spot-vaults/contracts/_test/LineHelpersTester.sol new file mode 100644 index 00000000..e3fbc9f6 --- /dev/null +++ b/spot-vaults/contracts/_test/LineHelpersTester.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import { LineHelpers } from "../_utils/LineHelpers.sol"; +import { Line, Range } from "../_interfaces/types/CommonTypes.sol"; + +contract LineHelpersTester { + using LineHelpers for Line; + + function testComputeY(Line memory fn, uint256 x) public pure returns (int256) { + return fn.computeY(x); + } + + function testAvgY( + Line memory fn, + uint256 xL, + uint256 xU + ) public pure returns (int256) { + return fn.avgY(xL, xU); + } + + function testComputePiecewiseAvgY( + Line memory fn1, + Line memory fn2, + Line memory fn3, + Range memory xBreakPt, + Range memory xRange + ) public pure returns (int256) { + return LineHelpers.computePiecewiseAvgY(fn1, fn2, fn3, xBreakPt, xRange); + } +} diff --git a/spot-vaults/contracts/_utils/AlphaVaultHelpers.sol b/spot-vaults/contracts/_utils/AlphaVaultHelpers.sol new file mode 100644 index 00000000..5cf119fb --- /dev/null +++ b/spot-vaults/contracts/_utils/AlphaVaultHelpers.sol @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { IAlphaProVault } from "../_interfaces/external/IAlphaProVault.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; + +/** + * @title AlphaVaultHelpers + * + * @notice Library with helper functions for Charm's Alpha Vaults. + * + */ +library AlphaVaultHelpers { + /// @dev Checks if the vault is underweight token0 (ie overweight token1). + function isUnderweightToken0(IAlphaProVault vault) internal view returns (bool) { + // `vault.getTwap()` returns the twap tick from the underlying univ3 pool. + // https://learn.charm.fi/charm/technical-references/core/alphaprovault#gettwap + int24 _priceTick = vault.getTwap(); + int24 _limitLower = vault.limitLower(); + int24 _limitUpper = vault.limitUpper(); + int24 _limitPriceTick = (_limitLower + _limitUpper) / 2; + // The limit range has more token1 than token0 if `_priceTick >= _limitPriceTick`, + // so the vault looks to sell token1. + return (_priceTick >= _limitPriceTick); + } + + /// @dev Removes the vault's limit range liquidity completely. + function removeLimitLiquidity(IAlphaProVault vault, IUniswapV3Pool pool) internal { + int24 _limitLower = vault.limitLower(); + int24 _limitUpper = vault.limitUpper(); + uint128 limitLiquidity = getLiquidity(vault, pool, _limitLower, _limitUpper); + // docs: https://learn.charm.fi/charm/technical-references/core/alphaprovault#emergencyburn + vault.emergencyBurn(_limitLower, _limitUpper, limitLiquidity); + } + + /// @dev Removes a percentage of the base and full range liquidity. + function trimLiquidity( + IAlphaProVault vault, + IUniswapV3Pool pool, + uint256 percToRemove, + uint256 one + ) internal { + if (percToRemove <= 0) { + return; + } + int24 _fullLower = vault.fullLower(); + int24 _fullUpper = vault.fullUpper(); + int24 _baseLower = vault.baseLower(); + int24 _baseUpper = vault.baseUpper(); + uint128 fullLiquidity = getLiquidity(vault, pool, _fullLower, _fullUpper); + uint128 baseLiquidity = getLiquidity(vault, pool, _baseLower, _baseUpper); + // Calculated baseLiquidityToBurn, baseLiquidityToBurn will be lesser than fullLiquidity, baseLiquidity + // Thus, there's no risk of overflow. + uint128 fullLiquidityToBurn = uint128( + Math.mulDiv(uint256(fullLiquidity), percToRemove, one) + ); + uint128 baseLiquidityToBurn = uint128( + Math.mulDiv(uint256(baseLiquidity), percToRemove, one) + ); + // docs: https://learn.charm.fi/charm/technical-references/core/alphaprovault#emergencyburn + // We remove the calculated percentage of base and full range liquidity. + if (fullLiquidityToBurn > 0) { + vault.emergencyBurn(_fullLower, _fullUpper, fullLiquidityToBurn); + } + if (baseLiquidityToBurn > 0) { + vault.emergencyBurn(_baseLower, _baseUpper, baseLiquidityToBurn); + } + } + + /// @dev A low-level method, which interacts directly with the vault and executes + /// a rebalance even when enough time hasn't elapsed since the last rebalance. + function forceRebalance(IAlphaProVault vault) internal { + uint32 _period = vault.period(); + vault.setPeriod(0); + vault.rebalance(); + vault.setPeriod(_period); + } + + /// @dev Wrapper around `IUniswapV3Pool.positions()`. + function getLiquidity( + IAlphaProVault vault, + IUniswapV3Pool pool, + int24 tickLower, + int24 tickUpper + ) internal view returns (uint128) { + bytes32 positionKey = keccak256( + abi.encodePacked(address(vault), tickLower, tickUpper) + ); + (uint128 liquidity, , , , ) = pool.positions(positionKey); + return liquidity; + } +} diff --git a/spot-vaults/contracts/_utils/LineHelpers.sol b/spot-vaults/contracts/_utils/LineHelpers.sol new file mode 100644 index 00000000..3eb077ce --- /dev/null +++ b/spot-vaults/contracts/_utils/LineHelpers.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import { MathHelpers } from "./MathHelpers.sol"; +import { Line, Range } from "../_interfaces/types/CommonTypes.sol"; +import { InvalidRange, UnexpectedRangeDelta } from "../_interfaces/errors/CommonErrors.sol"; + +/** + * @title LineHelpers + * + * @notice Library with helper functions for the Line data structure. + * + */ +library LineHelpers { + using Math for uint256; + using MathHelpers for uint256; + using SafeCast for uint256; + using SafeCast for int256; + + /// @dev This function computes y for a given x on the line (fn). + function computeY(Line memory fn, uint256 x) internal pure returns (int256) { + // If the line has a zero slope, return any y. + if (fn.y1 == fn.y2) { + return fn.y1.toInt256(); + } + + // m = dlY/dlX + // c = y2 - m . x2 + // y = m . x + c + int256 dlY = fn.y2.toInt256() - fn.y1.toInt256(); + int256 dlX = fn.x2.toInt256() - fn.x1.toInt256(); + int256 c = fn.y2.toInt256() - ((fn.x2.toInt256() * dlY) / dlX); + return (((x.toInt256() * dlY) / dlX) + c); + } + + /// @dev We compute the average height of the line between {xL,xU}. + function avgY(Line memory fn, uint256 xL, uint256 xU) internal pure returns (int256) { + // if the line has a zero slope, return any y + if (fn.y1 == fn.y2) { + return fn.y2.toInt256(); + } + + // NOTE: There is some precision loss because we cast to int and back + // m = dlY/dlX + // c = y2 - m . x2 + // Avg height => (yL + yU) / 2 + // => m . ( xL + xU ) / 2 + c + int256 dlY = fn.y2.toInt256() - fn.y1.toInt256(); + int256 dlX = fn.x2.toInt256() - fn.x1.toInt256(); + int256 c = fn.y2.toInt256() - ((fn.x2.toInt256() * dlY) / dlX); + return ((((xL + xU).toInt256() * dlY) / (2 * dlX)) + c); + } + + /// @notice Computes a piecewise average value (yVal) over the domain xRange, + /// based on three linear segments (fn1, fn2, fn3) that switch at xBreakPt. + /// @dev The function splits the input range into up to three segments, then + /// calculates a weighted average in each segment using the corresponding + /// piecewise function. + /// @dev AI-GENERATED + /// @param fn1 Piecewise linear function used when x is below xBreakPt.lower. + /// @param fn2 Piecewise linear function used when x is between xBreakPt.lower and xBreakPt.upper. + /// @param fn3 Piecewise linear function used when x is above xBreakPt.upper. + /// @param xBreakPt Range denoting the lower and upper x thresholds. + /// @param xRange The actual x-range over which we want to compute an averaged value. + /// @return yVal The computed piecewise average. + function computePiecewiseAvgY( + Line memory fn1, + Line memory fn2, + Line memory fn3, + Range memory xBreakPt, + Range memory xRange + ) internal pure returns (int256) { + int256 xl = xRange.lower.toInt256(); + int256 xu = xRange.upper.toInt256(); + int256 bpl = xBreakPt.lower.toInt256(); + int256 bpu = xBreakPt.upper.toInt256(); + + // Validate range inputs (custom errors omitted here). + if (xl > xu) revert InvalidRange(); + if (xl <= bpl && xu > bpu) revert UnexpectedRangeDelta(); + + // --------------------------- + // CASE A: Entire xRange below xBreakPt.lower → use fn1 + if (xu <= bpl) { + return avgY(fn1, xRange.lower, xRange.upper); + } + + // CASE B: xRange straddles bpl but still <= bpu + // Blend fn1 and fn2 + if (xl <= bpl && xu <= bpu) { + // w1 = portion in fn1, w2 = portion in fn2 + int256 w1 = bpl - xl; + int256 w2 = xu - bpl; + // Weighted average across two sub-ranges + return + (avgY(fn1, xRange.lower, xBreakPt.lower) * + w1 + + avgY(fn2, xBreakPt.lower, xRange.upper) * + w2) / (w1 + w2); + } + + // CASE C: Fully within [bpl, bpu] → use fn2 + if (xl > bpl && xu <= bpu) { + return avgY(fn2, xRange.lower, xRange.upper); + } + + // CASE D: xRange straddles xBreakPt.upper → blend fn2 and fn3 + if (xl <= bpu && xu > bpu) { + int256 w1 = bpu - xl; + int256 w2 = xu - bpu; + return + (avgY(fn2, xRange.lower, xBreakPt.upper) * + w1 + + avgY(fn3, xBreakPt.upper, xRange.upper) * + w2) / (w1 + w2); + } + + // CASE E: Entire xRange above xBreakPt.upper → use fn3 + // (if none of the above conditions matched, we must be here) + return avgY(fn3, xRange.lower, xRange.upper); + } +} diff --git a/spot-vaults/contracts/_utils/MathHelpers.sol b/spot-vaults/contracts/_utils/MathHelpers.sol new file mode 100644 index 00000000..4b7d3665 --- /dev/null +++ b/spot-vaults/contracts/_utils/MathHelpers.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; + +/** + * @title MathHelpers + * + * @notice Library with helper functions for math operations. + * + */ +library MathHelpers { + using Math for uint256; + using SafeCast for int256; + + /// @dev Clips a given integer number between provided min and max unsigned integer. + function clip(int256 n, uint256 min, uint256 max) internal pure returns (uint256) { + return clip(n > 0 ? n.toUint256() : 0, min, max); + } + + /// @dev Clips a given unsigned integer between provided min and max unsigned integer. + function clip(uint256 n, uint256 min, uint256 max) internal pure returns (uint256) { + return Math.min(Math.max(n, min), max); + } +} diff --git a/spot-vaults/contracts/_utils/UniswapV3PoolHelpers.sol b/spot-vaults/contracts/_utils/UniswapV3PoolHelpers.sol new file mode 100644 index 00000000..8c44d3cd --- /dev/null +++ b/spot-vaults/contracts/_utils/UniswapV3PoolHelpers.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable-next-line compiler-version +pragma solidity ^0.7.6; + +import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; +import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; + +/** + * @title UniswapV3PoolHelpers + * + * @notice Library with helper functions for a UniswapV3Pool. + * + */ +library UniswapV3PoolHelpers { + /// @notice Calculates the Time-Weighted Average Price (TWAP) given the TWAP tick and unit token amounts. + /// @param twapTick The Time-Weighted Average Price tick. + /// @param token0UnitAmt The fixed-point amount of token0 equivalent to 1.0. + /// @param token1UnitAmt The fixed-point amount of token1 equivalent to 1.0. + /// @param one 1.0 represented in the same fixed point denomination as calculated TWAP. + /// @return The computed TWAP price. + function calculateTwap( + int24 twapTick, + uint256 token0UnitAmt, + uint256 token1UnitAmt, + uint256 one + ) internal pure returns (uint256) { + uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(twapTick); + uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; + uint256 twapPrice = FullMath.mulDiv(one, (1 << 192), ratioX192); + return FullMath.mulDiv(twapPrice, token1UnitAmt, token0UnitAmt); + } + + /// @notice Retrieves the Time-Weighted Average Price (TWAP) tick from a Uniswap V3 pool over a given duration. + /// @param pool The Uniswap V3 pool. + /// @param twapDuration The TWAP duration. + /// @return The TWAP tick. + function getTwapTick( + IUniswapV3Pool pool, + uint32 twapDuration + ) internal view returns (int24) { + uint32[] memory secondsAgo = new uint32[](2); + secondsAgo[0] = twapDuration; + secondsAgo[1] = 0; + (int56[] memory tickCumulatives, ) = pool.observe(secondsAgo); + return int24((tickCumulatives[1] - tickCumulatives[0]) / twapDuration); + } +} diff --git a/spot-vaults/contracts/charm/UsdcSpotManager.sol b/spot-vaults/contracts/charm/UsdcSpotManager.sol new file mode 100644 index 00000000..17056faf --- /dev/null +++ b/spot-vaults/contracts/charm/UsdcSpotManager.sol @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { AlphaVaultHelpers } from "../_utils/AlphaVaultHelpers.sol"; +import { Range } from "../_interfaces/types/CommonTypes.sol"; + +import { IMetaOracle } from "../_interfaces/IMetaOracle.sol"; +import { IAlphaProVault } from "../_interfaces/external/IAlphaProVault.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; + +/// @title UsdcSpotManager +/// @notice This contract is a programmatic manager for the USDC-SPOT Charm AlphaProVault. +/// +/// @dev The vault's active zone is defined as lower and upper percentages of FMV. +/// For example, if the active zone is [0.95, 1.05]x and SPOT's FMV price is $1.35. +/// When the market price of SPOT is between [$1.28, $1.41] we consider price to be in the active zone. +/// +/// When in the active zone, the vault provides concentrated liquidity around the market price. +/// When price is outside the active zone, the vault reverts to a full range position. +/// +/// +contract UsdcSpotManager is Ownable { + //------------------------------------------------------------------------- + // Libraries + using AlphaVaultHelpers for IAlphaProVault; + using Math for uint256; + + //------------------------------------------------------------------------- + // Constants & Immutables + + /// @dev Decimals. + uint256 public constant DECIMALS = 18; + uint256 public constant ONE = (10 ** DECIMALS); + + /// @dev Vault parameter to set max full range weight (100%). + uint24 public constant VAULT_MAX_FRW = (10 ** 6); + int24 public constant POOL_MAX_TICK = 48000; // (-99.2/+12048.1%) + + /// @notice The USDC-SPOT charm alpha vault. + IAlphaProVault public immutable VAULT; + + /// @notice The underlying USDC-SPOT univ3 pool. + IUniswapV3Pool public immutable POOL; + + //------------------------------------------------------------------------- + // Storage + + /// @notice The meta oracle which returns prices of AMPL asset family. + IMetaOracle public oracle; + + /// @notice The lower and upper deviation factor within which + /// SPOT's price is considered to be in the active zone. + Range public activeZoneDeviation; + + /// @notice The width of concentrated liquidity band, + /// SPOT's price is in the active zone. + uint256 public concBandDeviationWidth; + + /// @notice The maximum USDC balance of the vault's full range position. + uint256 public fullRangeMaxUsdcBal; + + /// @notice The maximum percentage of vault's balanced assets in the full range position. + uint256 public fullRangeMaxPerc; + + /// @notice If price was within the active zone at the time of the last successful rebalance operation. + bool public prevWithinActiveZone; + + //----------------------------------------------------------------------------- + // Constructor and Initializer + + /// @notice Constructor initializes the contract with provided addresses. + /// @param vault_ Address of the AlphaProVault contract. + /// @param oracle_ Address of the MetaOracle contract. + constructor(IAlphaProVault vault_, IMetaOracle oracle_) Ownable() { + VAULT = vault_; + POOL = vault_.pool(); + + updateOracle(oracle_); + + prevWithinActiveZone = false; + activeZoneDeviation = Range({ + lower: ((ONE * 95) / 100), // 0.95 or 95% + upper: ((ONE * 105) / 100) // 1.05 or 105% + }); + concBandDeviationWidth = (ONE / 20); // 0.05 or 5% + fullRangeMaxUsdcBal = 250000 * (10 ** 6); // 250k USDC + fullRangeMaxPerc = (ONE / 2); // 0.5 or 50% + } + + //-------------------------------------------------------------------------- + // Owner only methods + + /// @notice Updates the MetaOracle. + function updateOracle(IMetaOracle oracle_) public onlyOwner { + // solhint-disable-next-line custom-errors + require(DECIMALS == oracle_.decimals(), "UnexpectedDecimals"); + oracle = oracle_; + } + + /// @notice Forwards the given calldata to the vault. + /// @param callData The calldata to pass to the vault. + /// @return The data returned by the vault method call. + function execOnVault( + bytes calldata callData + ) external onlyOwner returns (bytes memory) { + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory r) = address(VAULT).call(callData); + // solhint-disable-next-line custom-errors + require(success, "VaultExecutionFailed"); + return r; + } + + /// @notice Updates the active zone definition. + function updateActiveZone(Range memory activeZoneDeviation_) external onlyOwner { + activeZoneDeviation = activeZoneDeviation_; + } + + /// @notice Updates the width of the concentrated liquidity band. + function updateConcentratedBand(uint256 concBandDeviationWidth_) external onlyOwner { + concBandDeviationWidth = concBandDeviationWidth_; + } + + /// @notice Updates the absolute and percentage maximum amount of liquidity + /// in the full range liquidity band. + function updateFullRangeLiquidity( + uint256 fullRangeMaxUsdcBal_, + uint256 fullRangeMaxPerc_ + ) external onlyOwner { + // solhint-disable-next-line custom-errors + require(fullRangeMaxPerc_ <= ONE, "InvalidPerc"); + fullRangeMaxUsdcBal = fullRangeMaxUsdcBal_; + fullRangeMaxPerc = fullRangeMaxPerc_; + } + + //-------------------------------------------------------------------------- + // External write methods + + /// @notice Executes vault rebalance. + function rebalance() public { + (uint256 deviation, bool deviationValid) = oracle.spotPriceDeviation(); + bool withinActiveZone = (deviationValid && activeZone(deviation)); + bool shouldForceRebalance = (withinActiveZone != prevWithinActiveZone); + + // Set liquidity parameters. + withinActiveZone ? _setupActiveZoneLiq(deviation) : _resetLiq(); + + // Execute rebalance. + // NOTE: the vault.rebalance() will revert if enough time has not elapsed. + // We thus override with a force rebalance. + // https://learn.charm.fi/charm/technical-references/core/alphaprovault#rebalance + shouldForceRebalance ? VAULT.forceRebalance() : VAULT.rebalance(); + + // Trim positions after rebalance. + if (!withinActiveZone) { + VAULT.trimLiquidity(POOL, ONE - activeFullRangePerc(), ONE); + VAULT.removeLimitLiquidity(POOL); + } + + // Update valid rebalance state. + if (deviationValid) { + prevWithinActiveZone = withinActiveZone; + } + } + + //----------------------------------------------------------------------------- + // External/Public read methods + + /// @notice Based on the given deviation factor, + /// calculates if the pool needs to be in the active zone. + function activeZone(uint256 deviation) public view returns (bool) { + return (activeZoneDeviation.lower <= deviation && + deviation <= activeZoneDeviation.upper); + } + + /// @notice Computes the percentage of liquidity to be deployed into the full range, + /// based on owner defined maximums. + function activeFullRangePerc() public view returns (uint256) { + (uint256 usdcBal, ) = VAULT.getTotalAmounts(); + return Math.min(ONE.mulDiv(fullRangeMaxUsdcBal, usdcBal), fullRangeMaxPerc); + } + + /// @notice Checks the vault is overweight SPOT and looking to sell the extra SPOT for USDC. + function isOverweightSpot() public view returns (bool) { + // NOTE: In the underlying univ3 pool and token0 is USDC and token1 is SPOT. + // Underweight Token0 implies that the limit range has less USDC and more SPOT. + return VAULT.isUnderweightToken0(); + } + + /// @notice Calculates the Univ3 tick equivalent of the given deviation factor. + function deviationToTicks(uint256 deviation) public pure returns (int24) { + // 2% ~ 200 ticks -> (POOL.tickSpacing()) + // NOTE: width can't be zero, we set the minimum possible to 200. + uint256 t = deviation.mulDiv(10000, ONE); + t -= (t % 200); + return (t >= 200 ? SafeCast.toInt24(SafeCast.toInt256(t)) : int24(200)); + } + + /// @return Number of decimals representing 1.0. + function decimals() external pure returns (uint8) { + return uint8(DECIMALS); + } + + //----------------------------------------------------------------------------- + // Private methods + + /// @dev Configures the vault to provide concentrated liquidity in the active zone. + function _setupActiveZoneLiq(uint256 deviation) private { + VAULT.setFullRangeWeight( + SafeCast.toUint24(uint256(VAULT_MAX_FRW).mulDiv(activeFullRangePerc(), ONE)) + ); + + // IMPORTANT: + // + // If price is exactly at the bounds of `activeZoneDeviation`, + // the concentrated liquidity will be *at most* + // `deviationToTicks(concBandDeviationWidth/2)` outside the bounds. + // + VAULT.setBaseThreshold(deviationToTicks(concBandDeviationWidth)); + VAULT.setLimitThreshold( + deviationToTicks( + isOverweightSpot() + ? Math.max( + activeZoneDeviation.upper - deviation, + concBandDeviationWidth / 2 + ) + : Math.max( + deviation - activeZoneDeviation.lower, + concBandDeviationWidth / 2 + ) + ) + ); + } + + /// @dev Resets the vault to provide full range liquidity. + function _resetLiq() private { + VAULT.setFullRangeWeight(VAULT_MAX_FRW); + VAULT.setBaseThreshold(POOL_MAX_TICK); + VAULT.setLimitThreshold(POOL_MAX_TICK); + } +} diff --git a/spot-vaults/contracts/charm/WethWamplManager.sol b/spot-vaults/contracts/charm/WethWamplManager.sol new file mode 100644 index 00000000..7988596f --- /dev/null +++ b/spot-vaults/contracts/charm/WethWamplManager.sol @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.24; + +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { AlphaVaultHelpers } from "../_utils/AlphaVaultHelpers.sol"; +import { LineHelpers } from "../_utils/LineHelpers.sol"; +import { MathHelpers } from "../_utils/MathHelpers.sol"; +import { Line } from "../_interfaces/types/CommonTypes.sol"; + +import { IMetaOracle } from "../_interfaces/IMetaOracle.sol"; +import { IAlphaProVault } from "../_interfaces/external/IAlphaProVault.sol"; +import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; + +/// @title WethWamplManager +/// @notice This contract is a programmatic manager for the WETH-WAMPL Charm AlphaProVault. +contract WethWamplManager is Ownable { + //------------------------------------------------------------------------- + // Libraries + using AlphaVaultHelpers for IAlphaProVault; + using LineHelpers for Line; + using MathHelpers for int256; + + //------------------------------------------------------------------------- + // Constants & Immutables + + /// @dev Decimals. + uint256 public constant DECIMALS = 18; + uint256 public constant ONE = (10 ** DECIMALS); + + /// @dev At all times active liquidity percentage is no lower than 20%. + uint256 public constant MIN_ACTIVE_LIQ_PERC = ONE / 5; // 20% + + /// @notice The WETH-WAMPL charm alpha vault. + IAlphaProVault public immutable VAULT; + + /// @notice The underlying WETH-WAMPL univ3 pool. + IUniswapV3Pool public immutable POOL; + + //------------------------------------------------------------------------- + // Storage + + /// @notice The meta oracle which returns prices of AMPL asset family. + IMetaOracle public oracle; + + //------------------------------------------------------------------------- + // Active percentage calculation parameters + // + // The deviation factor (or deviation) is defined as the ratio between + // AMPL's current market price and its target price. + // The deviation is 1.0, when AMPL is at the target. + // + // The active liquidity percentage (a value between 20% to 100%) + // is computed based on pair-wise linear function, defined by the contract owner. + // + // If the current deviation is below ONE, function f1 is used + // else function f2 is used. Both f1 and f2 are defined by the owner. + // They are lines, with 2 {x,y} coordinates. The x coordinates are deviation factors, + // and y coordinates are active liquidity percentages. + // + // Both deviation and active liquidity percentage and represented internally + // as a fixed-point number with {DECIMALS} places. + // + + /// @notice Active percentage calculation function for when deviation is below ONE. + Line public activeLiqPercFn1; + + /// @notice Active percentage calculation function for when deviation is above ONE. + Line public activeLiqPercFn2; + + /// @notice The delta between the current and last recorded active liquidity percentage values + /// outside which a rebalance is executed forcefully. + uint256 public tolerableActiveLiqPercDelta; + + /// @notice The recorded deviation factor at the time of the last successful rebalance operation. + uint256 public prevDeviation; + + //----------------------------------------------------------------------------- + // Constructor and Initializer + + /// @notice Constructor initializes the contract with provided addresses. + /// @param vault_ Address of the AlphaProVault contract. + /// @param oracle_ Address of the MetaOracle contract. + constructor(IAlphaProVault vault_, IMetaOracle oracle_) Ownable() { + VAULT = vault_; + POOL = vault_.pool(); + + updateOracle(oracle_); + + activeLiqPercFn1 = Line({ + x1: ONE / 2, // 0.5 + y1: ONE / 5, // 20% + x2: ONE, // 1.0 + y2: ONE // 100% + }); + activeLiqPercFn2 = Line({ + x1: ONE, // 1.0 + y1: ONE, // 100% + x2: ONE * 2, // 2.0 + y2: ONE / 5 // 20% + }); + + tolerableActiveLiqPercDelta = ONE / 10; // 10% + prevDeviation = 0; + } + + //-------------------------------------------------------------------------- + // Owner only methods + + /// @notice Updates the MetaOracle. + function updateOracle(IMetaOracle oracle_) public onlyOwner { + // solhint-disable-next-line custom-errors + require(DECIMALS == oracle_.decimals(), "UnexpectedDecimals"); + oracle = oracle_; + } + + /// @notice Updates the vault's liquidity range parameters. + function setLiquidityRanges( + int24 baseThreshold, + uint24 fullRangeWeight, + int24 limitThreshold + ) external onlyOwner { + // Update liquidity parameters on the vault. + VAULT.setBaseThreshold(baseThreshold); + VAULT.setFullRangeWeight(fullRangeWeight); + VAULT.setLimitThreshold(limitThreshold); + } + + /// @notice Forwards the given calldata to the vault. + /// @param callData The calldata to pass to the vault. + /// @return The data returned by the vault method call. + function execOnVault( + bytes calldata callData + ) external onlyOwner returns (bytes memory) { + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory r) = address(VAULT).call(callData); + // solhint-disable-next-line custom-errors + require(success, "VaultExecutionFailed"); + return r; + } + + /// @notice Updates the active liquidity percentage calculation parameters. + function setActivePercParams( + uint256 tolerableActiveLiqPercDelta_, + Line memory activeLiqPercFn1_, + Line memory activeLiqPercFn2_ + ) external onlyOwner { + tolerableActiveLiqPercDelta = tolerableActiveLiqPercDelta_; + activeLiqPercFn1 = activeLiqPercFn1_; + activeLiqPercFn2 = activeLiqPercFn2_; + } + + //-------------------------------------------------------------------------- + // External write methods + + /// @notice Executes vault rebalance. + function rebalance() public { + // Get the current deviation factor. + (uint256 deviation, bool deviationValid) = oracle.amplPriceDeviation(); + + // Calculate the active liquidity percentages. + uint256 activeLiqPerc = deviationValid + ? computeActiveLiqPerc(deviation) + : MIN_ACTIVE_LIQ_PERC; + uint256 prevActiveLiqPerc = computeActiveLiqPerc(prevDeviation); + uint256 activeLiqPercDelta = (activeLiqPerc > prevActiveLiqPerc) + ? activeLiqPerc - prevActiveLiqPerc + : prevActiveLiqPerc - activeLiqPerc; + + // Execute rebalance. + // NOTE: the vault.rebalance() will revert if enough time has not elapsed. + // We thus override with a force rebalance. + // https://learn.charm.fi/charm/technical-references/core/alphaprovault#rebalance + (deviationValid && + shouldForceRebalance(deviation, prevDeviation, activeLiqPercDelta)) + ? VAULT.forceRebalance() + : VAULT.rebalance(); + + // Trim positions after rebalance. + VAULT.trimLiquidity(POOL, ONE - activeLiqPerc, ONE); + if (!deviationValid || shouldRemoveLimitRange(deviation)) { + VAULT.removeLimitLiquidity(POOL); + } + + // Update valid rebalance state. + if (deviationValid) { + prevDeviation = deviation; + } + } + + //----------------------------------------------------------------------------- + // External Public view methods + + /// @notice Computes active liquidity percentage based on the provided deviation factor. + /// @return The computed active liquidity percentage. + function computeActiveLiqPerc(uint256 deviation) public view returns (uint256) { + Line memory fn = (deviation <= ONE) ? activeLiqPercFn1 : activeLiqPercFn2; + return fn.computeY(deviation).clip(MIN_ACTIVE_LIQ_PERC, ONE); + } + + /// @notice Checks if a rebalance has to be forced. + function shouldForceRebalance( + uint256 deviation, + uint256 prevDeviation_, + uint256 activeLiqPercDelta + ) public view returns (bool) { + // We have to rebalance out of turn + // - if the active liquidity perc has deviated significantly, or + // - if the deviation factor has crossed ONE (in either direction). + return + (activeLiqPercDelta > tolerableActiveLiqPercDelta) || + ((deviation <= ONE && prevDeviation_ > ONE) || + (deviation >= ONE && prevDeviation_ < ONE)); + } + + /// @notice Checks if limit range liquidity needs to be removed. + function shouldRemoveLimitRange(uint256 deviation) public view returns (bool) { + // We only activate the limit range liquidity, when + // the vault sells WAMPL and deviation is above ONE, or when + // the vault buys WAMPL and deviation is below ONE + bool extraWampl = isOverweightWampl(); + bool activeLimitRange = ((deviation >= ONE && extraWampl) || + (deviation <= ONE && !extraWampl)); + return (!activeLimitRange); + } + + /// @notice Checks the vault is overweight WAMPL, + /// and looking to sell the extra WAMPL for WETH. + function isOverweightWampl() public view returns (bool) { + // NOTE: In the underlying univ3 pool and token0 is WETH and token1 is WAMPL. + // Underweight Token0 implies that the limit range has less WETH and more WAMPL. + return VAULT.isUnderweightToken0(); + } + + /// @return Number of decimals representing 1.0. + function decimals() external pure returns (uint8) { + return uint8(DECIMALS); + } +} diff --git a/spot-vaults/hardhat.config.ts b/spot-vaults/hardhat.config.ts index a9ad1cfa..d697b3bd 100644 --- a/spot-vaults/hardhat.config.ts +++ b/spot-vaults/hardhat.config.ts @@ -10,6 +10,7 @@ import "hardhat-gas-reporter"; // Loads custom tasks import "./tasks/deploy"; +import "./tasks/upgrade"; import "./tasks/ops"; import "./tasks/info"; import "./tasks/tools"; diff --git a/spot-vaults/package.json b/spot-vaults/package.json index b2915325..12986136 100644 --- a/spot-vaults/package.json +++ b/spot-vaults/package.json @@ -62,7 +62,7 @@ "ethers": "^6.6.0", "ethers-v5": "npm:ethers@^5.7.0", "ganache-cli": "latest", - "hardhat": "^2.22.8", + "hardhat": "^2.22.18", "hardhat-gas-reporter": "latest", "lodash": "^4.17.21", "prettier": "^2.7.1", diff --git a/spot-vaults/tasks/deploy.ts b/spot-vaults/tasks/deploy.ts index 1c609061..07ae73d6 100644 --- a/spot-vaults/tasks/deploy.ts +++ b/spot-vaults/tasks/deploy.ts @@ -17,52 +17,44 @@ task("deploy:mocks").setAction(async function (args: TaskArguments, hre) { await cpiOracle.mockData("1200000000000000000", true); }); -task("deploy:SpotAppraiser") - .addParam("perp", "the address of the perp token", undefined, types.string, false) - .addParam("usdOracle", "the address of the usd oracle", undefined, types.string, false) - .addParam("cpiOracle", "the address of the usd oracle", undefined, types.string, false) - .addParam("verify", "flag to set false for local deployments", true, types.boolean) - .setAction(async function (args: TaskArguments, hre) { - const deployer = (await hre.ethers.getSigners())[0]; - console.log("Signer", await deployer.getAddress()); - - const { perp, usdOracle, cpiOracle } = args; - - const SpotAppraiser = await hre.ethers.getContractFactory("SpotAppraiser"); - const spotAppraiser = await SpotAppraiser.deploy(perp, usdOracle, cpiOracle); - console.log("spotAppraiser", spotAppraiser.target); - - if (args.verify) { - await sleep(30); - await hre.run("verify:contract", { - address: spotAppraiser.target, - constructorArguments: [perp, usdOracle, cpiOracle], - }); - } else { - console.log("Skipping verification"); - } - }); - -task("deploy:SpotCDRPricer") - .addParam("perp", "the address of the perp token", undefined, types.string, false) +task("deploy:SpotPricer") + .addParam( + "wethWamplPool", + "the address of the weth-wampl univ3 pool", + undefined, + types.string, + false, + ) + .addParam( + "usdcSpotPool", + "the address of the usdc-spot univ3 pool", + undefined, + types.string, + false, + ) + .addParam("ethOracle", "the address of the eth oracle", undefined, types.string, false) .addParam("usdOracle", "the address of the usd oracle", undefined, types.string, false) - .addParam("cpiOracle", "the address of the usd oracle", undefined, types.string, false) .addParam("verify", "flag to set false for local deployments", true, types.boolean) .setAction(async function (args: TaskArguments, hre) { const deployer = (await hre.ethers.getSigners())[0]; console.log("Signer", await deployer.getAddress()); - const { perp, usdOracle, cpiOracle } = args; + const { wethWamplPool, usdcSpotPool, ethOracle, usdOracle } = args; - const SpotCDRPricer = await hre.ethers.getContractFactory("SpotCDRPricer"); - const spotCDRPricer = await SpotCDRPricer.deploy(perp, usdOracle, cpiOracle); - console.log("spotCDRPricer", spotCDRPricer.target); + const SpotPricer = await hre.ethers.getContractFactory("SpotPricer"); + const spotPricer = await SpotPricer.deploy( + wethWamplPool, + usdcSpotPool, + ethOracle, + usdOracle, + ); + console.log("spotPricer", spotPricer.target); if (args.verify) { await sleep(30); await hre.run("verify:contract", { - address: spotCDRPricer.target, - constructorArguments: [perp, usdOracle, cpiOracle], + address: spotPricer.target, + constructorArguments: [wethWamplPool, usdcSpotPool, ethOracle, usdOracle], }); } else { console.log("Skipping verification"); @@ -86,23 +78,17 @@ task("deploy:BillBroker") ) .addParam("usd", "the address of the usd token", undefined, types.string, false) .addParam("perp", "the address of the perp token", undefined, types.string, false) - .addParam( - "pricingStrategy", - "the address of the pricing strategy", - undefined, - types.string, - false, - ) + .addParam("oracle", "the address of the oracle", undefined, types.string, false) .addParam("verify", "flag to set false for local deployments", true, types.boolean) .setAction(async function (args: TaskArguments, hre) { const deployer = (await hre.ethers.getSigners())[0]; console.log("Signer", await deployer.getAddress()); - const { name, symbol, usd, perp, pricingStrategy } = args; + const { name, symbol, usd, perp, oracle } = args; const BillBroker = await hre.ethers.getContractFactory("BillBroker"); const billBroker = await hre.upgrades.deployProxy( BillBroker.connect(deployer), - [name, symbol, usd, perp, pricingStrategy], + [name, symbol, usd, perp, oracle], { initializer: "init(string,string,address,address,address)", }, @@ -119,69 +105,32 @@ task("deploy:BillBroker") } }); -task("deploy:WethWamplManager") - .addParam( - "vault", - "the address of the weth-wampl charm vault", - undefined, - types.string, - false, - ) - .addParam("cpiOracle", "the address of the usd oracle", undefined, types.string, false) - .addParam("ethOracle", "the address of the eth oracle", undefined, types.string, false) - .addParam("verify", "flag to set false for local deployments", true, types.boolean) - .setAction(async function (args: TaskArguments, hre) { - const deployer = (await hre.ethers.getSigners())[0]; - console.log("Signer", await deployer.getAddress()); - - const { vault, cpiOracle, ethOracle } = args; - - const WethWamplManager = await hre.ethers.getContractFactory("WethWamplManager"); - const manager = await WethWamplManager.deploy(vault, cpiOracle, ethOracle); - console.log("wethWamplManager", manager.target); - - if (args.verify) { - await sleep(30); - await hre.run("verify:contract", { - address: manager.target, - constructorArguments: [vault, cpiOracle, ethOracle], - }); - } else { - console.log("Skipping verification"); - } - }); - -task("deploy:UsdcSpotManager") - .addParam( - "vault", - "the address of the usdc-spot charm vault", - undefined, - types.string, - false, - ) +task("deploy:CharmManager") .addParam( - "spotAppraiser", - "the address of the spot appraiser", + "manager", + "the contract reference of the manager to be deployed", undefined, types.string, false, ) + .addParam("vault", "the address of the charm vault", undefined, types.string, false) + .addParam("oracle", "the address of the meta oracle", undefined, types.string, false) .addParam("verify", "flag to set false for local deployments", true, types.boolean) .setAction(async function (args: TaskArguments, hre) { const deployer = (await hre.ethers.getSigners())[0]; console.log("Signer", await deployer.getAddress()); - const { vault, spotAppraiser } = args; + const { manager, vault, oracle } = args; - const UsdcSpotManager = await hre.ethers.getContractFactory("UsdcSpotManager"); - const manager = await UsdcSpotManager.deploy(vault, spotAppraiser); - console.log("usdcSpotManager", manager.target); + const Factory = await hre.ethers.getContractFactory(manager); + const mgr = await Factory.deploy(vault, oracle); + console.log(manager, mgr.target); if (args.verify) { await sleep(30); await hre.run("verify:contract", { - address: manager.target, - constructorArguments: [vault, spotAppraiser], + address: mgr.target, + constructorArguments: [vault, oracle], }); } else { console.log("Skipping verification"); diff --git a/spot-vaults/tasks/info.ts b/spot-vaults/tasks/info.ts index 326c6e76..9cb18ac4 100644 --- a/spot-vaults/tasks/info.ts +++ b/spot-vaults/tasks/info.ts @@ -7,6 +7,68 @@ function pp(val, decimals) { return parseFloat(ethers.formatUnits(val, decimals)); } +task("info:MetaOracle") + .addPositionalParam( + "address", + "the address of the meta oracle contract", + undefined, + types.string, + false, + ) + .setAction(async function (args: TaskArguments, hre) { + const { address } = args; + + const oracle = await hre.ethers.getContractAt("IMetaOracle", address); + const oracleDecimals = await oracle.decimals(); + console.log("---------------------------------------------------------------"); + console.log("MetaOracle:", oracle.target); + + console.log("---------------------------------------------------------------"); + const usdcPriceData = await oracle.usdcPrice.staticCall(); + console.log("usdcPrice:", pp(usdcPriceData[0], oracleDecimals)); + + const ethPriceData = await oracle.ethUsdPrice.staticCall(); + console.log("ethPrice:", pp(ethPriceData[0], oracleDecimals)); + + const wamplPriceData = await oracle.wamplUsdPrice.staticCall(); + console.log("wamplPrice:", pp(wamplPriceData[0], oracleDecimals)); + + console.log("---------------------------------------------------------------"); + + const amplPriceData = await oracle.amplUsdPrice.staticCall(); + console.log("amplPrice:", pp(amplPriceData[0], oracleDecimals)); + + const amplTargetPriceData = await oracle.amplTargetUsdPrice.staticCall(); + console.log("amplTargetPrice:", pp(amplTargetPriceData[0], oracleDecimals)); + + const amplDeviationData = await oracle.amplPriceDeviation.staticCall(); + console.log("amplDeviation:", pp(amplDeviationData[0], oracleDecimals)); + + console.log("---------------------------------------------------------------"); + + const spotPriceData = await oracle.spotUsdPrice.staticCall(); + console.log("spotPrice:", pp(spotPriceData[0], oracleDecimals)); + + const spotFmvPriceData = await oracle.spotFmvUsdPrice.staticCall(); + console.log("spotFmvPrice:", pp(spotFmvPriceData[0], oracleDecimals)); + + const spotDeviationData = await oracle.spotPriceDeviation.staticCall(); + console.log("spotDeviation:", pp(spotDeviationData[0], oracleDecimals)); + + console.log("---------------------------------------------------------------"); + + const spotDeviation = pp(spotDeviationData[0], oracleDecimals); + const amplDeviation = pp(amplDeviationData[0], oracleDecimals); + const relativeDeviation = spotDeviation / amplDeviation; + + console.log("relativeDeviation:", relativeDeviation); + console.log("noArbZone:", relativeDeviation > 0.9 && relativeDeviation < 1.025); + console.log("flashMintZone:", relativeDeviation >= 1.025); + console.log("flashRedeemZone:", relativeDeviation <= 0.9); + + console.log("---------------------------------------------------------------"); + }); + task("info:BillBroker") .addPositionalParam( "address", @@ -31,21 +93,20 @@ task("info:BillBroker") const unitUsd = await billBroker.usdUnitAmt(); const unitPerp = await billBroker.perpUnitAmt(); - const pricingStrategy = await hre.ethers.getContractAt( - "SpotAppraiser", - await billBroker.pricingStrategy.staticCall(), + const oracle = await hre.ethers.getContractAt( + "SpotPricer", + // await billBroker.oracle.staticCall(), + "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881", ); - const pricingStrategyDecimals = await pricingStrategy.decimals(); + const oracleDecimals = await oracle.decimals(); console.log("---------------------------------------------------------------"); - console.log("pricingStrategy:", pricingStrategy.target); - console.log("owner:", await pricingStrategy.owner()); - const usdPriceCall = await pricingStrategy.usdPrice.staticCall(); - console.log("usdPrice:", pp(usdPriceCall[0], pricingStrategyDecimals)); + console.log("oracle:", oracle.target); + const usdPriceCall = await oracle.usdPrice.staticCall(); + console.log("usdPrice:", pp(usdPriceCall[0], oracleDecimals)); console.log("usdPriceValid:", usdPriceCall[1]); - const perpPriceCall = await pricingStrategy.perpPrice.staticCall(); - console.log("perpPrice:", pp(perpPriceCall[0], pricingStrategyDecimals)); + const perpPriceCall = await oracle.perpUsdPrice.staticCall(); + console.log("perpPrice:", pp(perpPriceCall[0], oracleDecimals)); console.log("perpPriceValid:", perpPriceCall[1]); - console.log("isSpotHealthy:", await pricingStrategy.isSPOTHealthy.staticCall()); console.log("---------------------------------------------------------------"); console.log("BillBroker:", billBroker.target); console.log("owner:", await billBroker.owner()); @@ -143,24 +204,15 @@ task("info:WethWamplManager") const { address } = args; const manager = await hre.ethers.getContractAt("WethWamplManager", address); + const oracle = await hre.ethers.getContractAt("IMetaOracle", await manager.oracle()); const managerDecimals = await manager.decimals(); console.log("---------------------------------------------------------------"); console.log("WethWamplManager:", manager.target); console.log("owner:", await manager.owner()); - console.log("cpiOracle:", await manager.cpiOracle()); - console.log("ethOracle:", await manager.ethOracle()); + console.log("oracle:", oracle.target); console.log("---------------------------------------------------------------"); - const ethPriceData = await manager.getEthUSDPrice(); - console.log("ethPrice:", pp(ethPriceData[0], managerDecimals)); - - const wamplPrice = await manager.getWamplUSDPrice(ethPriceData[0]); - console.log("wamplPrice:", pp(wamplPrice, managerDecimals)); - - const amplPrice = await manager.getAmplUSDPrice(ethPriceData[0]); - console.log("amplPrice:", pp(amplPrice, managerDecimals)); - - const r = await manager.computeDeviationFactor.staticCall(); + const r = await oracle.amplPriceDeviation.staticCall(); const deviation = r[0]; console.log("dataValid:", r[1]); console.log("isOverweightWampl:", await manager.isOverweightWampl()); @@ -193,22 +245,25 @@ task("info:UsdcSpotManager") const { address } = args; const manager = await hre.ethers.getContractAt("UsdcSpotManager", address); + const oracle = await hre.ethers.getContractAt("IMetaOracle", await manager.oracle()); const managerDecimals = await manager.decimals(); console.log("---------------------------------------------------------------"); console.log("UsdcSpotManager:", manager.target); console.log("owner:", await manager.owner()); + console.log("oracle:", oracle.target); console.log("---------------------------------------------------------------"); - const spotPrice = await manager.getSpotUSDPrice(); - console.log("spotPrice:", pp(spotPrice, managerDecimals)); - - const r = await manager.computeDeviationFactor.staticCall(); + const r = await oracle.spotPriceDeviation.staticCall(); const deviation = r[0]; console.log("dataValid:", r[1]); console.log("isOverweightSpot:", await manager.isOverweightSpot()); - console.log("prevDeviation:", pp(await manager.prevDeviation(), managerDecimals)); + console.log("prevWithinActiveZone:", await manager.prevWithinActiveZone()); + console.log("withinActiveZone:", await manager.activeZone(deviation)); console.log("deviation:", pp(deviation, managerDecimals)); - + console.log( + "fullRangePerc:", + pp(await manager.activeFullRangePerc(), managerDecimals), + ); let rebalanceActive = true; try { await manager.rebalance.staticCall(); diff --git a/spot-vaults/tasks/scripts/mainnet.sh b/spot-vaults/tasks/scripts/mainnet.sh index bc4b46b0..9b0eb47f 100644 --- a/spot-vaults/tasks/scripts/mainnet.sh +++ b/spot-vaults/tasks/scripts/mainnet.sh @@ -1,40 +1,45 @@ ######################################################################## ## DEPLOYMENT -yarn hardhat --network mainnet deploy:SpotAppraiser \ - --perp "0xC1f33e0cf7e40a67375007104B929E49a581bafE" \ - --usd-oracle "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6" \ - --cpi-oracle "0x2A18bfb505b49AED12F19F271cC1183F98ff4f71" +yarn hardhat --network mainnet deploy:SpotPricer \ + --weth-wampl-pool "0x0c2b6bf7322a3cceb47c7ba74f2c75a19f530f11" \ + --usdc-spot-pool "0x898adc9aa0c23dce3fed6456c34dbe2b57784325" \ + --eth-oracle "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" \ + --usd-oracle "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6" yarn hardhat --network mainnet deploy:BillBroker \ --name "Bill Broker USDC-SPOT LP" \ --symbol "BB-USDC-SPOT" \ --usd "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" \ --perp "0xC1f33e0cf7e40a67375007104B929E49a581bafE" \ - --pricing-strategy "0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c" + --oracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" -yarn hardhat --network mainnet transferOwnership "0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c" \ - --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" +yarn hardhat --network mainnet deploy:CharmManager \ + --manager "WethWamplManager" \ + --vault "0x9658B5bdCad59Dd0b7b936d955E5dF81eA2B4DcB" \ + --oracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" + +yarn hardhat --network mainnet deploy:CharmManager \ + --manager "UsdcSpotManager" \ + --vault "0x2dcaff0f75765d7867887fc402b71c841b3a4bfb" \ + --oracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" yarn hardhat --network mainnet transferOwnership "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" \ --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" -yarn hardhat --network mainnet transferOwnership "0xF6E42F7a83fCfB1Bd28aC209fD4a849f54bD1044" \ +yarn hardhat --network mainnet transferOwnership "0x574fca658b4B59E965C0e5f74761AE0Ac41DA6a7" \ --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" -yarn hardhat --network mainnet deploy:WethWamplManager \ - --vault "0x9658B5bdCad59Dd0b7b936d955E5dF81eA2B4DcB" \ - --cpi-oracle "0x2A18bfb505b49AED12F19F271cC1183F98ff4f71" \ - --eth-oracle "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" - -yarn hardhat --network mainnet transferOwnership "0x803094e6427c0bd10398236433F6c18B7aBf98ab" \ +yarn hardhat --network mainnet transferOwnership "0x2f67158859Fe0f69f5773570eC60444Fe0c1693c" \ --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" ######################################################################## ## INFO +yarn hardhat --network mainnet info:MetaOracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" yarn hardhat --network mainnet info:BillBroker "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" -yarn hardhat --network mainnet info:WethWamplManager "0x803094e6427c0bd10398236433F6c18B7aBf98ab" +yarn hardhat --network mainnet info:WethWamplManager "0x574fca658b4B59E965C0e5f74761AE0Ac41DA6a7" +yarn hardhat --network mainnet info:UsdcSpotManager "0x2f67158859Fe0f69f5773570eC60444Fe0c1693c" ######################################################################## ## OPS @@ -54,4 +59,10 @@ yarn hardhat --network mainnet ops:swapPerpsForUSD \ yarn hardhat --network mainnet ops:redeem \ --address "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" \ - --amount 1000 \ No newline at end of file + --amount 1000 + +######################################################################## +## Upgrade + +yarn hardhat --network mainnet validate_upgrade BillBroker "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" +yarn hardhat --network mainnet prepare_upgrade BillBroker "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" \ No newline at end of file diff --git a/spot-vaults/tasks/upgrade.ts b/spot-vaults/tasks/upgrade.ts new file mode 100644 index 00000000..d47cdd94 --- /dev/null +++ b/spot-vaults/tasks/upgrade.ts @@ -0,0 +1,119 @@ +import { getAdminAddress, getImplementationAddress } from "@openzeppelin/upgrades-core"; +import { task, types } from "hardhat/config"; +import { TaskArguments } from "hardhat/types"; +import { sleep } from "./tools"; + +task("validate_upgrade") + .addPositionalParam( + "factory", + "the name of the factory", + undefined, + types.string, + false, + ) + .addPositionalParam( + "address", + "the address of the deployed proxy contract", + undefined, + types.string, + false, + ) + .setAction(async function (args: TaskArguments, hre) { + const { factory, address } = args; + const Factory = await hre.ethers.getContractFactory(factory); + console.log("Trying strict validation"); + try { + await hre.upgrades.validateUpgrade(address, Factory); + } catch (e) { + console.log("Strict validation failed. ", e); + console.log("Retrying but allowing variable renames."); + await hre.upgrades.validateUpgrade(address, Factory, { + unsafeAllowRenames: true, + }); + } + console.log("Success"); + }); + +task("prepare_upgrade") + .addPositionalParam( + "factory", + "the name of the factory", + undefined, + types.string, + false, + ) + .addPositionalParam( + "address", + "the address of the deployed proxy contract", + undefined, + types.string, + false, + ) + .addParam("fromIdx", "the index of sender", 0, types.int) + .setAction(async function (args: TaskArguments, hre) { + const { factory, address } = args; + + const signer = (await hre.ethers.getSigners())[args.fromIdx]; + const signerAddress = await signer.getAddress(); + console.log("Signer", signerAddress); + + console.log("Proxy Admin", await getAdminAddress(hre.ethers.provider, address)); + + const Factory = await hre.ethers.getContractFactory(factory); + const newImpl = await hre.upgrades.prepareUpgrade(address, Factory, { + unsafeAllowRenames: true, + }); + console.log("Deploying using", factory); + console.log("New implementation at:", newImpl); + + console.log("Update implementation by running the following:"); + console.log(`proxyAdmin.upgrade(${address}, ${newImpl})`); + + await sleep(15); + await hre.run("verify:contract", { + address: newImpl, + }); + }); + +task("upgrade:testnet") + .addPositionalParam( + "factory", + "the name of the factory", + undefined, + types.string, + false, + ) + .addPositionalParam( + "address", + "the address of the deployed proxy contract", + undefined, + types.string, + false, + ) + .addParam("fromIdx", "the index of sender", 0, types.int) + .setAction(async function (args: TaskArguments, hre) { + const signer = (await hre.ethers.getSigners())[args.fromIdx]; + const signerAddress = await signer.getAddress(); + console.log("Signer", signerAddress); + + const { factory, address } = args; + const Factory = await hre.ethers.getContractFactory(factory); + + console.log("Proxy", address); + console.log( + "Current implementation", + await getImplementationAddress(hre.ethers.provider, address), + ); + + const impl = await hre.upgrades.upgradeProxy(address, Factory, { + unsafeAllowRenames: true, + }); + await impl.deployed(); + const newImpl = await getImplementationAddress(hre.ethers.provider, address); + console.log("Updated implementation", newImpl); + + await sleep(15); + await hre.run("verify:contract", { + address: newImpl, + }); + }); diff --git a/spot-vaults/test/BillBroker.ts b/spot-vaults/test/BillBroker.ts index 230b794e..71c2afd0 100644 --- a/spot-vaults/test/BillBroker.ts +++ b/spot-vaults/test/BillBroker.ts @@ -1,7 +1,7 @@ import { ethers, upgrades } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { expect } from "chai"; -import { DMock, usdFP, perpFP, percentageFP, priceFP } from "./helpers"; +import { DMock, usdFP, perpFP, percFP, priceFP } from "./helpers"; describe("BillBroker", function () { async function setupContracts() { @@ -13,30 +13,28 @@ describe("BillBroker", function () { await usd.init("USD token", "usd", 6); const perp = await Token.deploy(); await perp.init("Perp token", "perp", 9); - const pricingStrategy = new DMock("SpotAppraiser"); - await pricingStrategy.deploy(); - await pricingStrategy.mockMethod("decimals()", [18]); - await pricingStrategy.mockMethod("perpPrice()", [0, false]); - await pricingStrategy.mockMethod("usdPrice()", [0, false]); + const oracle = new DMock("IPerpPricer"); + await oracle.deploy(); + await oracle.mockMethod("decimals()", [18]); + await oracle.mockMethod("perpFmvUsdPrice()", [0, false]); + await oracle.mockMethod("usdPrice()", [0, false]); const BillBroker = await ethers.getContractFactory("BillBroker"); const billBroker = await upgrades.deployProxy( BillBroker.connect(deployer), - ["BillBroker LP", "LP token", usd.target, perp.target, pricingStrategy.target], + ["BillBroker LP", "LP token", usd.target, perp.target, oracle.target], { initializer: "init(string,string,address,address,address)", }, ); - return { deployer, usd, perp, pricingStrategy, billBroker }; + return { deployer, usd, perp, oracle, billBroker }; } describe("init", function () { it("should set initial values", async function () { - const { deployer, billBroker, usd, pricingStrategy } = await loadFixture( - setupContracts, - ); + const { deployer, billBroker, usd, oracle } = await loadFixture(setupContracts); expect(await billBroker.usd()).to.eq(usd.target); - expect(await billBroker.pricingStrategy()).to.eq(pricingStrategy.target); + expect(await billBroker.oracle()).to.eq(oracle.target); expect(await billBroker.usdUnitAmt()).to.eq(usdFP("1")); expect(await billBroker.perpUnitAmt()).to.eq(perpFP("1")); @@ -44,20 +42,20 @@ describe("BillBroker", function () { expect(await billBroker.keeper()).to.eq(await deployer.getAddress()); const arHardBound = await billBroker.arHardBound(); - expect(arHardBound.upper).to.eq(ethers.MaxUint256); - expect(arHardBound.lower).to.eq(0n); + expect(arHardBound.upper).to.eq(ethers.MaxInt256); + expect(arHardBound.lower).to.eq(0); const arSoftBound = await billBroker.arSoftBound(); - expect(arSoftBound.upper).to.eq(ethers.MaxUint256); - expect(arSoftBound.lower).to.eq(0n); + expect(arSoftBound.upper).to.eq(ethers.MaxInt256); + expect(arSoftBound.lower).to.eq(0); const fees = await billBroker.fees(); expect(fees.mintFeePerc).to.eq(0); expect(fees.burnFeePerc).to.eq(0); - expect(fees.perpToUSDSwapFeePercs.lower).to.eq(percentageFP("1")); - expect(fees.perpToUSDSwapFeePercs.upper).to.eq(percentageFP("1")); - expect(fees.usdToPerpSwapFeePercs.lower).to.eq(percentageFP("1")); - expect(fees.usdToPerpSwapFeePercs.upper).to.eq(percentageFP("1")); + expect(fees.perpToUSDSwapFeeFactors.lower).to.eq(percFP("1")); + expect(fees.perpToUSDSwapFeeFactors.upper).to.eq(percFP("1")); + expect(fees.usdToPerpSwapFeeFactors.lower).to.eq(percFP("1")); + expect(fees.usdToPerpSwapFeeFactors.upper).to.eq(percFP("1")); expect(fees.protocolSwapSharePerc).to.eq(0); expect(await billBroker.usdBalance()).to.eq(0n); @@ -85,35 +83,35 @@ describe("BillBroker", function () { }); }); - describe("#updatePricingStrategy", function () { + describe("#updateOracle", function () { describe("when triggered by non-owner", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.renounceOwnership(); - await expect( - billBroker.updatePricingStrategy(ethers.ZeroAddress), - ).to.be.revertedWith("Ownable: caller is not the owner"); + await expect(billBroker.updateOracle(ethers.ZeroAddress)).to.be.revertedWith( + "Ownable: caller is not the owner", + ); }); }); - describe("when pricing strategy is not valid", function () { + describe("when oracle is not valid", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - const pricingStrategy = new DMock("SpotAppraiser"); - await pricingStrategy.deploy(); - await pricingStrategy.mockMethod("decimals()", [17]); + const oracle = new DMock("SpotPricer"); + await oracle.deploy(); + await oracle.mockMethod("decimals()", [17]); await expect( - billBroker.updatePricingStrategy(pricingStrategy.target), + billBroker.updateOracle(oracle.target), ).to.be.revertedWithCustomError(billBroker, "UnexpectedDecimals"); }); it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - const pricingStrategy = new DMock("SpotAppraiser"); - await pricingStrategy.deploy(); - await pricingStrategy.mockMethod("decimals()", [18]); + const oracle = new DMock("SpotPricer"); + await oracle.deploy(); + await oracle.mockMethod("decimals()", [18]); - await billBroker.updatePricingStrategy(pricingStrategy.target); - expect(await billBroker.pricingStrategy()).to.eq(pricingStrategy.target); + await billBroker.updateOracle(oracle.target); + expect(await billBroker.oracle()).to.eq(oracle.target); }); }); }); @@ -122,17 +120,17 @@ describe("BillBroker", function () { let fees: any; beforeEach(async function () { fees = { - mintFeePerc: percentageFP("0.005"), - burnFeePerc: percentageFP("0.025"), - perpToUSDSwapFeePercs: { - lower: percentageFP("0.01"), - upper: percentageFP("0.1"), + mintFeePerc: percFP("0.005"), + burnFeePerc: percFP("0.025"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.01"), + upper: percFP("1.1"), }, - usdToPerpSwapFeePercs: { - lower: percentageFP("0.02"), - upper: percentageFP("0.2"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.02"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.05"), + protocolSwapSharePerc: percFP("0.05"), }; }); @@ -149,7 +147,7 @@ describe("BillBroker", function () { describe("when parameters are invalid", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - fees.mintFeePerc = percentageFP("1.01"); + fees.mintFeePerc = percFP("1.01"); await expect(billBroker.updateFees(fees)).to.be.revertedWithCustomError( billBroker, "InvalidPerc", @@ -160,7 +158,7 @@ describe("BillBroker", function () { describe("when parameters are invalid", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - fees.burnFeePerc = percentageFP("1.01"); + fees.burnFeePerc = percFP("1.01"); await expect(billBroker.updateFees(fees)).to.be.revertedWithCustomError( billBroker, "InvalidPerc", @@ -168,8 +166,8 @@ describe("BillBroker", function () { }); it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - fees.perpToUSDSwapFeePercs.lower = percentageFP("0.2"); - fees.perpToUSDSwapFeePercs.upper = percentageFP("0.1"); + fees.perpToUSDSwapFeeFactors.lower = percFP("0.2"); + fees.perpToUSDSwapFeeFactors.upper = percFP("0.1"); await expect(billBroker.updateFees(fees)).to.be.revertedWithCustomError( billBroker, "InvalidPerc", @@ -177,8 +175,8 @@ describe("BillBroker", function () { }); it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - fees.usdToPerpSwapFeePercs.lower = percentageFP("0.2"); - fees.usdToPerpSwapFeePercs.upper = percentageFP("0.1"); + fees.usdToPerpSwapFeeFactors.lower = percFP("0.2"); + fees.usdToPerpSwapFeeFactors.upper = percFP("0.1"); await expect(billBroker.updateFees(fees)).to.be.revertedWithCustomError( billBroker, "InvalidPerc", @@ -186,7 +184,7 @@ describe("BillBroker", function () { }); it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); - fees.protocolSwapSharePerc = percentageFP("1.01"); + fees.protocolSwapSharePerc = percFP("1.01"); await expect(billBroker.updateFees(fees)).to.be.revertedWithCustomError( billBroker, "InvalidPerc", @@ -201,10 +199,10 @@ describe("BillBroker", function () { const f = await billBroker.fees(); expect(f.mintFeePerc).to.eq(fees.mintFeePerc); expect(f.burnFeePerc).to.eq(fees.burnFeePerc); - expect(f.perpToUSDSwapFeePercs.lower).to.eq(fees.perpToUSDSwapFeePercs.lower); - expect(f.perpToUSDSwapFeePercs.upper).to.eq(fees.perpToUSDSwapFeePercs.upper); - expect(f.usdToPerpSwapFeePercs.lower).to.eq(fees.usdToPerpSwapFeePercs.lower); - expect(f.usdToPerpSwapFeePercs.upper).to.eq(fees.usdToPerpSwapFeePercs.upper); + expect(f.perpToUSDSwapFeeFactors.lower).to.eq(fees.perpToUSDSwapFeeFactors.lower); + expect(f.perpToUSDSwapFeeFactors.upper).to.eq(fees.perpToUSDSwapFeeFactors.upper); + expect(f.usdToPerpSwapFeeFactors.lower).to.eq(fees.usdToPerpSwapFeeFactors.lower); + expect(f.usdToPerpSwapFeeFactors.upper).to.eq(fees.usdToPerpSwapFeeFactors.upper); expect(f.protocolSwapSharePerc).to.eq(fees.protocolSwapSharePerc); }); }); @@ -217,8 +215,8 @@ describe("BillBroker", function () { await billBroker.renounceOwnership(); await expect( billBroker.updateARBounds( - [percentageFP("0.9"), percentageFP("1.1")], - [percentageFP("0.8"), percentageFP("1.2")], + [percFP("0.9"), percFP("1.1")], + [percFP("0.8"), percFP("1.2")], ), ).to.be.revertedWith("Ownable: caller is not the owner"); }); @@ -229,8 +227,8 @@ describe("BillBroker", function () { const { billBroker } = await loadFixture(setupContracts); await expect( billBroker.updateARBounds( - [percentageFP("1.1"), percentageFP("1.0")], - [percentageFP("0.8"), percentageFP("1.2")], + [percFP("1.1"), percFP("1.0")], + [percFP("0.8"), percFP("1.2")], ), ).to.be.revertedWithCustomError(billBroker, "InvalidARBound"); }); @@ -239,8 +237,8 @@ describe("BillBroker", function () { const { billBroker } = await loadFixture(setupContracts); await expect( billBroker.updateARBounds( - [percentageFP("0.9"), percentageFP("1.1")], - [percentageFP("1.2"), percentageFP("0.8")], + [percFP("0.9"), percFP("1.1")], + [percFP("1.2"), percFP("0.8")], ), ).to.be.revertedWithCustomError(billBroker, "InvalidARBound"); }); @@ -249,8 +247,8 @@ describe("BillBroker", function () { const { billBroker } = await loadFixture(setupContracts); await expect( billBroker.updateARBounds( - [percentageFP("0.9"), percentageFP("0.8")], - [percentageFP("1.1"), percentageFP("1.2")], + [percFP("0.9"), percFP("0.8")], + [percFP("1.1"), percFP("1.2")], ), ).to.be.revertedWithCustomError(billBroker, "InvalidARBound"); }); @@ -259,8 +257,8 @@ describe("BillBroker", function () { const { billBroker } = await loadFixture(setupContracts); await expect( billBroker.updateARBounds( - [percentageFP("0.8"), percentageFP("1.2")], - [percentageFP("0.9"), percentageFP("1.1")], + [percFP("0.8"), percFP("1.2")], + [percFP("0.9"), percFP("1.1")], ), ).to.be.revertedWithCustomError(billBroker, "InvalidARBound"); }); @@ -270,16 +268,16 @@ describe("BillBroker", function () { it("should update bound", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.updateARBounds( - [percentageFP("0.9"), percentageFP("1.1")], - [percentageFP("0.8"), percentageFP("1.2")], + [percFP("0.9"), percFP("1.1")], + [percFP("0.8"), percFP("1.2")], ); const b1 = await billBroker.arSoftBound(); - expect(b1.lower).to.eq(percentageFP("0.9")); - expect(b1.upper).to.eq(percentageFP("1.1")); + expect(b1.lower).to.eq(percFP("0.9")); + expect(b1.upper).to.eq(percFP("1.1")); const b2 = await billBroker.arHardBound(); - expect(b2.lower).to.eq(percentageFP("0.8")); - expect(b2.upper).to.eq(percentageFP("1.2")); + expect(b2.lower).to.eq(percFP("0.8")); + expect(b2.upper).to.eq(percFP("1.2")); }); }); }); @@ -346,8 +344,8 @@ describe("BillBroker", function () { describe("#usdPrice", function () { describe("when the price is invalid", function () { it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("usdPrice()", [priceFP("1"), false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("usdPrice()", [priceFP("1"), false]); await expect(billBroker.usdPrice()).to.be.revertedWithCustomError( billBroker, "UnreliablePrice", @@ -357,8 +355,8 @@ describe("BillBroker", function () { describe("when the price is valid", function () { it("should return strategy price", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("usdPrice()", [priceFP("1.001"), true]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("usdPrice()", [priceFP("1.001"), true]); expect(await billBroker.usdPrice.staticCall()).to.eq(priceFP("1.001")); }); }); @@ -367,8 +365,8 @@ describe("BillBroker", function () { describe("#perpPrice", function () { describe("when the price is invalid", function () { it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("perpPrice()", [priceFP("1.17"), false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("perpFmvUsdPrice()", [priceFP("1.17"), false]); await expect(billBroker.perpPrice()).to.be.revertedWithCustomError( billBroker, "UnreliablePrice", @@ -378,8 +376,8 @@ describe("BillBroker", function () { describe("when the price is valid", function () { it("should return strategy price", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("perpPrice()", [priceFP("1.17"), true]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("perpFmvUsdPrice()", [priceFP("1.17"), true]); expect(await billBroker.perpPrice.staticCall()).to.eq(priceFP("1.17")); }); }); @@ -403,235 +401,314 @@ describe("BillBroker", function () { describe("#reserveState", function () { it("should return the reserve state", async function () { - const { billBroker, perp, usd, pricingStrategy } = await loadFixture( - setupContracts, - ); + const { billBroker, perp, usd, oracle } = await loadFixture(setupContracts); await usd.mint(billBroker.target, usdFP("115")); await perp.mint(billBroker.target, perpFP("100")); - await pricingStrategy.mockMethod("usdPrice()", [priceFP("1"), true]); - await pricingStrategy.mockMethod("perpPrice()", [priceFP("1.3"), true]); - const r = { - usdBalance: await billBroker.usdBalance(), - perpBalance: await billBroker.perpBalance(), - usdPrice: await billBroker.usdPrice.staticCall(), - perpPrice: await billBroker.perpPrice.staticCall(), - }; - expect(r.usdBalance).to.eq(usdFP("115")); - expect(r.perpBalance).to.eq(perpFP("100")); - expect(r.usdPrice).to.eq(priceFP("1")); - expect(r.perpPrice).to.eq(priceFP("1.3")); + await oracle.mockMethod("usdPrice()", [priceFP("1"), true]); + await oracle.mockMethod("perpFmvUsdPrice()", [priceFP("1.3"), true]); + const r = await billBroker.reserveState.staticCall(); + expect(r[0]).to.eq(usdFP("115")); + expect(r[1]).to.eq(perpFP("100")); + expect(r[2]).to.eq(priceFP("1")); + expect(r[3]).to.eq(priceFP("1.3")); }); }); - describe("#computeUSDToPerpSwapFeePerc", function () { - it("should compute the right fee perc", async function () { + describe("#computeUSDToPerpSwapFeeFactor", function () { + it("should compute the right factor perc", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.updateARBounds( - [percentageFP("0.75"), percentageFP("1.25")], - [percentageFP("0.5"), percentageFP("1.5")], + [percFP("0.75"), percFP("1.25")], + [percFP("0.25"), percFP("4")], ); await billBroker.updateFees({ mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.16"), }, - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("1.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.08"), }, protocolSwapSharePerc: 0n, }); await expect( - billBroker.computeUSDToPerpSwapFeePerc(percentageFP("1.5"), percentageFP("0.5")), - ).to.be.revertedWithCustomError(billBroker, "UnexpectedARDelta"); + billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.5"), percFP("0.5")), + ).to.be.revertedWithCustomError(billBroker, "InvalidRange"); await expect( - billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.25"), - percentageFP("1.249"), - ), - ).to.be.revertedWithCustomError(billBroker, "UnexpectedARDelta"); + billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.25"), percFP("1.249")), + ).to.be.revertedWithCustomError(billBroker, "InvalidRange"); + await expect( + billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.75"), percFP("1.26")), + ).to.be.revertedWithCustomError(billBroker, "UnexpectedRangeDelta"); + await expect( + billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.5"), percFP("1.5")), + ).to.be.revertedWithCustomError(billBroker, "UnexpectedRangeDelta"); + + expect( + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.1"), percFP("0.26")), + ).to.eq(percFP("0.84")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("0.25"), - percentageFP("1.2"), - ), - ).to.eq(percentageFP("0.05")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.3"), percFP("0.5")), + ).to.eq(percFP("0.8955")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("0.25"), - percentageFP("1.25"), - ), - ).to.eq(percentageFP("0.05")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.25"), percFP("1")), + ).to.eq(percFP("0.963333333333333333")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.2"), - percentageFP("1.3"), - ), - ).to.eq(percentageFP("0.1225")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.25"), percFP("1.24")), + ).to.eq(percFP("0.978282828282828282")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.3"), - percentageFP("1.45"), - ), - ).to.eq(percentageFP("0.775")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("0.76"), percFP("1.24")), + ).to.eq(percFP("1.025")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.3"), - percentageFP("1.5"), - ), - ).to.eq(percentageFP("0.92")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.2"), percFP("1.3")), + ).to.eq(percFP("1.02525")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("0.5"), - percentageFP("1.5"), - ), - ).to.eq(percentageFP("0.23125")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.3"), percFP("1.45")), + ).to.eq(percFP("1.0275")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.3"), - percentageFP("1.501"), - ), - ).to.eq(percentageFP("1")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.3"), percFP("1.5")), + ).to.eq(percFP("1.028")); expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1.3"), - percentageFP("2"), - ), - ).to.eq(percentageFP("1")); + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.3"), percFP("1.501")), + ).to.eq(percFP("1.02801")); + expect( + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.3"), percFP("2")), + ).to.eq(percFP("1.033")); + expect( + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.5"), percFP("4")), + ).to.eq(percFP("1.055")); + expect( + await billBroker.computeUSDToPerpSwapFeeFactor(percFP("1.3"), percFP("4.01")), + ).to.eq(percFP("2")); }); - it("should compute the right fee perc when outside bounds", async function () { - const { billBroker } = await loadFixture(setupContracts); - await billBroker.updateARBounds( - [percentageFP("0.75"), percentageFP("1.25")], - [percentageFP("0"), percentageFP("10")], - ); + describe("Extended coverage for break-point conditions & edge cases", function () { + let billBroker; - await billBroker.updateFees({ - mintFeePerc: 0n, - burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, - }, - usdToPerpSwapFeePercs: { - lower: percentageFP("1.01"), - upper: percentageFP("2"), - }, - protocolSwapSharePerc: 0n, + beforeEach(async () => { + const fixtures = await loadFixture(setupContracts); + billBroker = fixtures.billBroker; + + await billBroker.updateARBounds( + [percFP("0.75"), percFP("1.25")], + [percFP("0.25"), percFP("4")], + ); + + await billBroker.updateFees({ + mintFeePerc: 0n, + burnFeePerc: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.0769"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1693"), + }, + protocolSwapSharePerc: 0n, + }); + }); + + it("Case A: Entire range below arSoftBound.lower => uses fn1 entirely", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("0.50"), + percFP("0.55"), + ); + expect(result).to.eq(percFP("0.979145")); }); - expect( - await billBroker.computeUSDToPerpSwapFeePerc( - percentageFP("1"), - percentageFP("1.25"), - ), - ).to.eq(percentageFP("1")); + it("Case B: Range straddles arSoftBound.lower => partial weighting fn1/fn2", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("0.70"), + percFP("0.80"), + ); + expect(result).to.eq(percFP("1.0224525")); + }); + + it("Case C: Range fully within [arSoftBound.lower..arSoftBound.upper] => uses fn2 entirely", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("1.0"), + percFP("1.2"), + ); + expect(result).to.eq(percFP("1.025")); + }); + + it("Case D: Range straddles arSoftBound.upper => partial weighting fn2/fn3", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("1.20"), + percFP("1.30"), + ); + expect(result).to.eq(percFP("1.025655909090909091")); + }); + + it("Case E: Entire range above arSoftBound.upper => uses fn3 entirely", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("1.5"), + percFP("3"), + ); + expect(result).to.eq(percFP("1.077472727272727273")); + }); + + it("Zero-length range at boundary (e.g., arPre=arPost=arSoftBound.lower) => picks boundary side", async () => { + const result = await billBroker.computeUSDToPerpSwapFeeFactor( + percFP("0.75"), + percFP("0.75"), + ); + expect(result).to.eq(percFP("1.025")); + }); }); }); - describe("#computePerpToUSDSwapFeePerc", function () { - it("should compute the right fee perc", async function () { + describe("#computePerpToUSDSwapFeeFactor", function () { + it("should compute the right fee factor", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.updateARBounds( - [percentageFP("0.75"), percentageFP("1.25")], - [percentageFP("0.5"), percentageFP("1.5")], + [percFP("0.75"), percFP("1.25")], + [percFP("0.25"), percFP("4")], ); await billBroker.updateFees({ mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.15"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), }, protocolSwapSharePerc: 0n, }); await expect( - billBroker.computePerpToUSDSwapFeePerc(percentageFP("0.5"), percentageFP("1.5")), - ).to.be.revertedWithCustomError(billBroker, "UnexpectedARDelta"); + billBroker.computePerpToUSDSwapFeeFactor(percFP("1.25"), percFP("1.251")), + ).to.be.revertedWithCustomError(billBroker, "InvalidRange"); await expect( - billBroker.computePerpToUSDSwapFeePerc( - percentageFP("1.25"), - percentageFP("1.251"), - ), - ).to.be.revertedWithCustomError(billBroker, "UnexpectedARDelta"); + billBroker.computePerpToUSDSwapFeeFactor(percFP("1.5"), percFP("0.5")), + ).to.be.revertedWithCustomError(billBroker, "UnexpectedRangeDelta"); expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("2"), - percentageFP("0.8"), - ), - ).to.eq(percentageFP("0.1")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("4"), percFP("3")), + ).to.eq(percFP("0.854545454545454545")); + + expect( + await billBroker.computePerpToUSDSwapFeeFactor(percFP("4"), percFP("1.25")), + ).to.eq(percFP("0.95")); + expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("1.45"), - percentageFP("0.8"), - ), - ).to.eq(percentageFP("0.1")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("3"), percFP("2")), + ).to.eq(percFP("0.963636363636363636")); + expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("0.8"), - percentageFP("0.7"), - ), - ).to.eq(percentageFP("0.12")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("2"), percFP("1.5")), + ).to.eq(percFP("1.045454545454545454")); + expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("0.8"), - percentageFP("0.5"), - ), - ).to.eq(percentageFP("0.266666666666666666")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("2"), percFP("0.8")), + ).to.eq(percFP("1.074431818181818181")); + expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("1.5"), - percentageFP("0.5"), - ), - ).to.eq(percentageFP("0.15")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("1.45"), percFP("0.8")), + ).to.eq(percFP("1.096643356643356643")); + + expect( + await billBroker.computePerpToUSDSwapFeeFactor(percFP("1.25"), percFP("0.9")), + ).to.eq(percFP("1.1")); + + expect( + await billBroker.computePerpToUSDSwapFeeFactor(percFP("0.8"), percFP("0.7")), + ).to.eq(percFP("1.10125")); + expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("1.0"), - percentageFP("0.49"), - ), - ).to.eq(percentageFP("1")); + await billBroker.computePerpToUSDSwapFeeFactor(percFP("0.8"), percFP("0.5")), + ).to.eq(percFP("1.110416666666666666")); + + expect( + await billBroker.computePerpToUSDSwapFeeFactor(percFP("1.0"), percFP("0.49")), + ).to.eq(percFP("1.106627450980392156")); }); - it("should compute the right fee perc when outside bounds", async function () { - const { billBroker } = await loadFixture(setupContracts); - await billBroker.updateARBounds( - [percentageFP("0.75"), percentageFP("1.25")], - [percentageFP("0"), percentageFP("10")], - ); + describe("Extended coverage for break-point conditions & edge cases", function () { + let billBroker; - await billBroker.updateFees({ - mintFeePerc: 0n, - burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: percentageFP("1.01"), - upper: percentageFP("2"), - }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, - }, - protocolSwapSharePerc: 0n, + beforeEach(async () => { + const fixtures = await loadFixture(setupContracts); + billBroker = fixtures.billBroker; + + await billBroker.updateARBounds( + [percFP("0.75"), percFP("1.25")], + [percFP("0.25"), percFP("4")], + ); + + await billBroker.updateFees({ + mintFeePerc: 0n, + burnFeePerc: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.0769"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1693"), + }, + protocolSwapSharePerc: 0n, + }); + }); + + it("Case A: Entirely below arSoftBound.lower => uses fn1 for perp->USD swap", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("0.60"), + percFP("0.50"), + ); + expect(result).to.eq(percFP("1.04576")); }); - expect( - await billBroker.computePerpToUSDSwapFeePerc( - percentageFP("1.25"), - percentageFP("1.11"), - ), - ).to.eq(percentageFP("1")); + it("Case B: Straddles arSoftBound.lower => partial weighting", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("0.80"), + percFP("0.70"), + ); + expect(result).to.eq(percFP("1.0262975")); + }); + + it("Case C: Fully within [0.75..1.25] => uses middle fn2", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("1.20"), + percFP("1.10"), + ); + expect(result).to.eq(percFP("1.025")); + }); + + it("Case D: Straddles arSoftBound.upper => partial weighting", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("1.30"), + percFP("1.20"), + ); + expect(result).to.eq(percFP("1.024116818181818182")); + }); + + it("Case E: Entirely above arSoftBound.upper => uses fn3", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("2.50"), + percFP("2.0"), + ); + expect(result).to.eq(percFP("0.954345454545454546")); + }); + + it("Zero-length range exactly at boundary => picks boundary side", async () => { + const result = await billBroker.computePerpToUSDSwapFeeFactor( + percFP("1.25"), + percFP("1.25"), + ); + expect(result).to.eq(percFP("1.025")); + }); }); }); }); diff --git a/spot-vaults/test/BillBroker_deposit_redeem.ts b/spot-vaults/test/BillBroker_deposit_redeem.ts index 784f65a9..8832fc8d 100644 --- a/spot-vaults/test/BillBroker_deposit_redeem.ts +++ b/spot-vaults/test/BillBroker_deposit_redeem.ts @@ -1,7 +1,7 @@ import { ethers, upgrades } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { expect } from "chai"; -import { DMock, usdFP, perpFP, lpAmtFP, percentageFP, priceFP } from "./helpers"; +import { DMock, usdFP, perpFP, lpAmtFP, percFP, priceFP } from "./helpers"; describe("BillBroker", function () { async function setupContracts() { @@ -14,16 +14,16 @@ describe("BillBroker", function () { await usd.init("USD token", "usd", 6); const perp = await Token.deploy(); await perp.init("Perp token", "perp", 9); - const pricingStrategy = new DMock("SpotAppraiser"); - await pricingStrategy.deploy(); - await pricingStrategy.mockMethod("decimals()", [18]); - await pricingStrategy.mockMethod("perpPrice()", [priceFP("1.15"), true]); - await pricingStrategy.mockMethod("usdPrice()", [priceFP("1"), true]); + const oracle = new DMock("IPerpPricer"); + await oracle.deploy(); + await oracle.mockMethod("decimals()", [18]); + await oracle.mockMethod("perpFmvUsdPrice()", [priceFP("1.15"), true]); + await oracle.mockMethod("usdPrice()", [priceFP("1"), true]); const BillBroker = await ethers.getContractFactory("BillBroker"); const billBroker = await upgrades.deployProxy( BillBroker.connect(deployer), - ["BillBroker LP", "LP token", usd.target, perp.target, pricingStrategy.target], + ["BillBroker LP", "LP token", usd.target, perp.target, oracle.target], { initializer: "init(string,string,address,address,address)", }, @@ -31,13 +31,13 @@ describe("BillBroker", function () { await billBroker.updateFees({ mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, protocolSwapSharePerc: 0n, }); @@ -45,7 +45,7 @@ describe("BillBroker", function () { await perp.mint(await deployer.getAddress(), perpFP("2000")); await usd.mint(await otherUser.getAddress(), usdFP("2000")); await perp.mint(await otherUser.getAddress(), perpFP("2000")); - return { deployer, otherUser, usd, perp, pricingStrategy, billBroker }; + return { deployer, otherUser, usd, perp, oracle, billBroker }; } async function assetRatio(billBroker) { @@ -145,15 +145,15 @@ describe("BillBroker", function () { perpFP("100"), ); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: percFP("0.1"), burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, protocolSwapSharePerc: 0n, }); @@ -180,7 +180,7 @@ describe("BillBroker", function () { await billBroker.swapUSDForPerps(usdFP("115"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - expect(await assetRatio(billBroker)).to.eq(ethers.MaxUint256); + expect(await assetRatio(billBroker)).to.eq(ethers.MaxInt256); const r = await billBroker.computeMintAmt.staticCall(usdFP("100"), 0n); expect(r[0]).to.eq(lpAmtFP("93.478260869565217391304347")); @@ -234,45 +234,49 @@ describe("BillBroker", function () { it("should return the mint amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); await usd.approve(billBroker.target, usdFP("115")); - await perp.approve(billBroker.target, perpFP("200")); + await perp.approve(billBroker.target, perpFP("2000")); await billBroker.deposit( usdFP("115"), - perpFP("200"), + perpFP("2000"), usdFP("115"), - perpFP("200"), + perpFP("2000"), ); expect(await billBroker.computeMintAmtWithUSD.staticCall(usdFP("11.5"))).to.eq( - lpAmtFP("10.5"), + lpAmtFP("10.071428571428571428571427"), ); }); }); - describe("when fee > 0", function () { + describe("when swapFee > 0", function () { it("should return the mint amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); + await billBroker.updateARBounds( + [percFP("0.9"), percFP("1.1")], + [percFP("0.25"), percFP("4")], + ); await usd.approve(billBroker.target, usdFP("115")); - await perp.approve(billBroker.target, perpFP("200")); + await perp.approve(billBroker.target, perpFP("2000")); await billBroker.deposit( usdFP("115"), - perpFP("200"), + perpFP("2000"), usdFP("115"), - perpFP("200"), + perpFP("2000"), ); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1.2"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.15"), }, protocolSwapSharePerc: 0n, }); expect(await billBroker.computeMintAmtWithUSD.staticCall(usdFP("11.5"))).to.eq( - lpAmtFP("9.45"), + lpAmtFP("11.980204248447204967542855"), ); }); }); @@ -321,46 +325,50 @@ describe("BillBroker", function () { describe("when fee = 0", function () { it("should return the mint amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await usd.approve(billBroker.target, usdFP("200")); + await usd.approve(billBroker.target, usdFP("2000")); await perp.approve(billBroker.target, perpFP("100")); await billBroker.deposit( - usdFP("200"), + usdFP("2000"), perpFP("100"), - usdFP("200"), + usdFP("2000"), perpFP("100"), ); expect(await billBroker.computeMintAmtWithPerp.staticCall(perpFP("10.5"))).to.eq( - lpAmtFP("11.5"), + lpAmtFP("11.989361702127659574468084"), ); }); }); - describe("when fee > 0", function () { + describe("when swapFee > 0", function () { it("should return the mint amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await usd.approve(billBroker.target, usdFP("200")); + await billBroker.updateARBounds( + [percFP("0.9"), percFP("1.1")], + [percFP("0.25"), percFP("4")], + ); + await usd.approve(billBroker.target, usdFP("2000")); await perp.approve(billBroker.target, perpFP("100")); await billBroker.deposit( - usdFP("200"), + usdFP("2000"), perpFP("100"), - usdFP("200"), + usdFP("2000"), perpFP("100"), ); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1.2"), }, protocolSwapSharePerc: 0n, }); expect(await billBroker.computeMintAmtWithPerp.staticCall(perpFP("10.5"))).to.eq( - lpAmtFP("10.35"), + lpAmtFP("14.243163296689361701442552"), ); }); }); @@ -381,7 +389,7 @@ describe("BillBroker", function () { await billBroker.swapUSDForPerps(usdFP("115"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - expect(await assetRatio(billBroker)).to.eq(ethers.MaxUint256); + expect(await assetRatio(billBroker)).to.eq(ethers.MaxInt256); expect(await billBroker.computeMintAmtWithPerp.staticCall(perpFP("100"))).to.eq( lpAmtFP("107.5"), ); @@ -565,15 +573,15 @@ describe("BillBroker", function () { it("should withhold fees and mint lp tokens", async function () { const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, protocolSwapSharePerc: 0n, }); @@ -581,7 +589,7 @@ describe("BillBroker", function () { await perp.approve(billBroker.target, perpFP("100")); await expect(() => billBroker.deposit(usdFP("115"), perpFP("100"), usdFP("115"), perpFP("100")), - ).to.changeTokenBalance(billBroker, deployer, lpAmtFP("193.49")); + ).to.changeTokenBalance(billBroker, deployer, lpAmtFP("214.99")); }); }); @@ -601,7 +609,7 @@ describe("BillBroker", function () { await billBroker.swapUSDForPerps(usdFP("115"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - expect(await assetRatio(billBroker)).to.eq(ethers.MaxUint256); + expect(await assetRatio(billBroker)).to.eq(ethers.MaxInt256); await usd.approve(billBroker.target, usdFP("115")); await expect(() => @@ -645,15 +653,14 @@ describe("BillBroker", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.pause(); - await expect(billBroker.depositUSD(usdFP("115"), percentageFP("1"))).to.be - .reverted; + await expect(billBroker.depositUSD(usdFP("115"), percFP("1"))).to.be.reverted; }); }); describe("when usdAmtIn is zero", function () { it("should return zero", async function () { const { billBroker } = await loadFixture(setupContracts); - const r = await billBroker.depositUSD.staticCall(0n, percentageFP("1")); + const r = await billBroker.depositUSD.staticCall(0n, percFP("1")); expect(r).to.eq(0n); }); }); @@ -671,7 +678,7 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("100")); expect( - await billBroker.depositUSD.staticCall(usdFP("100"), ethers.MaxUint256), + await billBroker.depositUSD.staticCall(usdFP("100"), ethers.MaxInt256), ).to.eq(0n); }); }); @@ -689,7 +696,7 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("100")); expect( - await billBroker.depositUSD.staticCall(usdFP("100"), ethers.MaxUint256), + await billBroker.depositUSD.staticCall(usdFP("100"), ethers.MaxInt256), ).to.eq(0n); }); }); @@ -707,7 +714,7 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("1")); expect( - await billBroker.depositUSD.staticCall(usdFP("1"), ethers.MaxUint256), + await billBroker.depositUSD.staticCall(usdFP("1"), ethers.MaxInt256), ).to.eq(0n); }); }); @@ -725,7 +732,7 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("115")); expect( - await billBroker.depositUSD.staticCall(usdFP("115"), ethers.MaxUint256), + await billBroker.depositUSD.staticCall(usdFP("115"), ethers.MaxInt256), ).to.eq(lpAmtFP("105")); }); }); @@ -744,7 +751,7 @@ describe("BillBroker", function () { await usd.approve(billBroker.target, usdFP("10")); await expect( - billBroker.depositUSD(usdFP("10"), percentageFP("0.50")), + billBroker.depositUSD(usdFP("10"), percFP("0.50")), ).to.be.revertedWithCustomError(billBroker, "SlippageTooHigh"); }); }); @@ -763,7 +770,7 @@ describe("BillBroker", function () { await usd.approve(billBroker.target, usdFP("10")); await expect(() => - billBroker.depositUSD(usdFP("10"), percentageFP("1")), + billBroker.depositUSD(usdFP("10"), percFP("1")), ).to.changeTokenBalance(usd, deployer, usdFP("-10")); }); @@ -780,14 +787,14 @@ describe("BillBroker", function () { await usd.approve(billBroker.target, usdFP("10")); await expect(() => - billBroker.depositUSD(usdFP("10"), percentageFP("1")), + billBroker.depositUSD(usdFP("10"), percFP("1")), ).to.changeTokenBalance( billBroker, deployer, - lpAmtFP("9.130434782608695652173913"), + lpAmtFP("9.130434782608695652173912"), ); expect(await billBroker.totalSupply()).to.eq( - lpAmtFP("324.130434782608695652173913"), + lpAmtFP("324.130434782608695652173912"), ); }); @@ -803,11 +810,11 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("10")); const r = await billBroker.reserveState.staticCall(); - await expect(billBroker.depositUSD(usdFP("10"), percentageFP("1"))) + await expect(billBroker.depositUSD(usdFP("10"), percFP("1"))) .to.emit(billBroker, "DepositUSD") .withArgs(usdFP("10"), r); expect(await billBroker.totalSupply()).to.eq( - lpAmtFP("324.130434782608695652173913"), + lpAmtFP("324.130434782608695652173912"), ); }); @@ -823,8 +830,8 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("10")); - const r = await billBroker.depositUSD.staticCall(usdFP("10"), percentageFP("1")); - expect(r).to.eq(lpAmtFP("9.130434782608695652173913")); + const r = await billBroker.depositUSD.staticCall(usdFP("10"), percFP("1")); + expect(r).to.eq(lpAmtFP("9.130434782608695652173912")); }); }); @@ -832,15 +839,56 @@ describe("BillBroker", function () { it("should withhold fees and mint lp tokens", async function () { const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: 0n, + burnFeePerc: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), + }, + protocolSwapSharePerc: 0n, + }); + + await usd.approve(billBroker.target, usdFP("115")); + await perp.approve(billBroker.target, perpFP("200")); + await billBroker.deposit( + usdFP("115"), + perpFP("200"), + usdFP("115"), + perpFP("200"), + ); + + await usd.approve(billBroker.target, usdFP("10")); + await expect(() => + billBroker.depositUSD(usdFP("10"), percFP("1")), + ).to.changeTokenBalance( + billBroker, + deployer, + lpAmtFP("8.984877117391304347826085"), + ); + + const r = await billBroker.computeRedemptionAmts.staticCall( + lpAmtFP("8.984877117391304347826085"), + ); + expect(r[0]).to.eq(usdFP("3.466549")); + expect(r[1]).to.eq(perpFP("5.546479327")); + }); + + it("should be roughly equivalent to swap+deposit", async function () { + const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); + await billBroker.updateFees({ + mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), }, protocolSwapSharePerc: 0n, }); @@ -855,13 +903,20 @@ describe("BillBroker", function () { ); await usd.approve(billBroker.target, usdFP("10")); + await perp.approve(billBroker.target, perpFP("10")); + await billBroker.swapUSDForPerps(usdFP("6.535"), 0n); await expect(() => - billBroker.depositUSD(usdFP("10"), percentageFP("1")), + billBroker.deposit(usdFP("3.465"), percFP("10"), 0n, 0n), ).to.changeTokenBalance( billBroker, deployer, - lpAmtFP("7.395652173913043478260868"), + lpAmtFP("8.980746287077796519521125"), + ); + const r = await billBroker.computeRedemptionAmts.staticCall( + lpAmtFP("8.980746287077796519521125"), ); + expect(r[0]).to.eq(usdFP("3.464999")); + expect(r[1]).to.eq(perpFP("5.544098565")); }); }); }); @@ -871,15 +926,14 @@ describe("BillBroker", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.pause(); - await expect(billBroker.depositPerp(perpFP("100"), percentageFP("1"))).to.be - .reverted; + await expect(billBroker.depositPerp(perpFP("100"), percFP("1"))).to.be.reverted; }); }); describe("when perpAmtIn is zero", function () { it("should return zero", async function () { const { billBroker } = await loadFixture(setupContracts); - const r = await billBroker.depositPerp.staticCall(0n, percentageFP("1")); + const r = await billBroker.depositPerp.staticCall(0n, percFP("1")); expect(r).to.eq(0n); }); }); @@ -940,7 +994,7 @@ describe("BillBroker", function () { await billBroker.deposit(usdFP("115"), perpFP("90"), usdFP("115"), perpFP("90")); await perp.approve(billBroker.target, perpFP("10")); expect(await billBroker.depositPerp.staticCall(perpFP("10"), 0n)).to.eq( - lpAmtFP("10.789473684210526315789473"), + lpAmtFP("10.789473684210526315789472"), ); }); }); @@ -959,7 +1013,7 @@ describe("BillBroker", function () { await perp.approve(billBroker.target, perpFP("10")); await expect( - billBroker.depositPerp(perpFP("10"), percentageFP("1.85")), + billBroker.depositPerp(perpFP("10"), percFP("1.85")), ).to.be.revertedWithCustomError(billBroker, "SlippageTooHigh"); }); }); @@ -978,7 +1032,7 @@ describe("BillBroker", function () { await perp.approve(billBroker.target, perpFP("10")); await expect(() => - billBroker.depositPerp(perpFP("10"), percentageFP("1")), + billBroker.depositPerp(perpFP("10"), percFP("1")), ).to.changeTokenBalance(perp, deployer, perpFP("-10")); }); @@ -995,7 +1049,7 @@ describe("BillBroker", function () { await perp.approve(billBroker.target, perpFP("10")); await expect(() => - billBroker.depositPerp(perpFP("10"), percentageFP("1")), + billBroker.depositPerp(perpFP("10"), percFP("1")), ).to.changeTokenBalance(billBroker, deployer, lpAmtFP("11")); expect(await billBroker.totalSupply()).to.eq(lpAmtFP("341")); }); @@ -1013,7 +1067,7 @@ describe("BillBroker", function () { await perp.approve(billBroker.target, perpFP("10")); const r = await billBroker.reserveState.staticCall(); - await expect(billBroker.depositPerp(perpFP("10"), percentageFP("1"))) + await expect(billBroker.depositPerp(perpFP("10"), percFP("1"))) .to.emit(billBroker, "DepositPerp") .withArgs(perpFP("10"), r); expect(await billBroker.totalSupply()).to.eq(lpAmtFP("341")); @@ -1031,10 +1085,7 @@ describe("BillBroker", function () { ); await perp.approve(billBroker.target, perpFP("10")); - const r = await billBroker.depositPerp.staticCall( - perpFP("10"), - percentageFP("1"), - ); + const r = await billBroker.depositPerp.staticCall(perpFP("10"), percFP("1")); expect(r).to.eq(lpAmtFP("11")); }); }); @@ -1052,22 +1103,69 @@ describe("BillBroker", function () { ); await billBroker.updateFees({ - mintFeePerc: percentageFP("0.1"), + mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), }, protocolSwapSharePerc: 0n, }); await perp.approve(billBroker.target, perpFP("10")); await expect(() => - billBroker.depositPerp(perpFP("10"), percentageFP("1")), - ).to.changeTokenBalance(billBroker, deployer, lpAmtFP("9.9")); + billBroker.depositPerp(perpFP("10"), percFP("1")), + ).to.changeTokenBalance(billBroker, deployer, lpAmtFP("10.825833333315")); + + const r = await billBroker.computeRedemptionAmts.staticCall( + lpAmtFP("10.825833333315"), + ); + expect(r[0]).to.eq(usdFP("7.305613")); + expect(r[1]).to.eq(perpFP("3.493988865")); + }); + + it("should be roughly equivalent to swap+deposit", async function () { + const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); + await usd.approve(billBroker.target, usdFP("230")); + await perp.approve(billBroker.target, perpFP("100")); + await billBroker.deposit( + usdFP("230"), + perpFP("100"), + usdFP("230"), + perpFP("100"), + ); + + await billBroker.updateFees({ + mintFeePerc: 0n, + burnFeePerc: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), + }, + protocolSwapSharePerc: 0n, + }); + await perp.approve(billBroker.target, perpFP("15")); + await usd.approve(billBroker.target, usdFP("15")); + await billBroker.swapPerpsForUSD(perpFP("6"), 0n); + await expect(() => + billBroker.deposit(usdFP("7.30"), percFP("5"), 0n, 0n), + ).to.changeTokenBalance( + billBroker, + deployer, + lpAmtFP("10.789506096809951964527651"), + ); + const r = await billBroker.computeRedemptionAmts.staticCall( + lpAmtFP("10.789506096809951964527651"), + ); + expect(r[0]).to.eq(usdFP("7.299999")); + expect(r[1]).to.eq(perpFP("3.465720140")); }); }); }); @@ -1129,14 +1227,14 @@ describe("BillBroker", function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); await billBroker.updateFees({ mintFeePerc: 0n, - burnFeePerc: percentageFP("0.1"), - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + burnFeePerc: percFP("0.1"), + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, protocolSwapSharePerc: 0n, }); @@ -1170,15 +1268,7 @@ describe("BillBroker", function () { await billBroker.swapUSDForPerps(usdFP("115"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - const s = await billBroker.reserveState.staticCall(); - expect( - await billBroker.assetRatio({ - usdBalance: s[0], - perpBalance: s[1], - usdPrice: s[2], - perpPrice: s[3], - }), - ).to.eq(ethers.MaxUint256); + expect(await assetRatio(billBroker)).to.eq(ethers.MaxInt256); const r = await billBroker.computeRedemptionAmts.staticCall(lpAmtFP("100")); expect(r[0]).to.eq(usdFP("106.976744")); @@ -1202,15 +1292,7 @@ describe("BillBroker", function () { await billBroker.swapPerpsForUSD(perpFP("100"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); - const s = await billBroker.reserveState.staticCall(); - expect( - await billBroker.assetRatio({ - usdBalance: s[0], - perpBalance: s[1], - usdPrice: s[2], - perpPrice: s[3], - }), - ).to.eq(0); + expect(await assetRatio(billBroker)).to.eq(0); const r = await billBroker.computeRedemptionAmts.staticCall(lpAmtFP("100")); expect(r[0]).to.eq(0n); @@ -1426,15 +1508,7 @@ describe("BillBroker", function () { await billBroker.swapUSDForPerps(usdFP("115"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - const s = await billBroker.reserveState.staticCall(); - expect( - await billBroker.assetRatio({ - usdBalance: s[0], - perpBalance: s[1], - usdPrice: s[2], - perpPrice: s[3], - }), - ).to.eq(ethers.MaxUint256); + expect(await assetRatio(billBroker)).to.eq(ethers.MaxInt256); const perpBal = await perp.balanceOf(await deployer.getAddress()); await expect(() => billBroker.redeem(lpAmtFP("100"))).to.changeTokenBalance( @@ -1463,15 +1537,7 @@ describe("BillBroker", function () { await billBroker.swapPerpsForUSD(perpFP("100"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); - const s = await billBroker.reserveState.staticCall(); - expect( - await billBroker.assetRatio({ - usdBalance: s[0], - perpBalance: s[1], - usdPrice: s[2], - perpPrice: s[3], - }), - ).to.eq(0); + expect(await assetRatio(billBroker)).to.eq(0); const usdBal = await usd.balanceOf(await deployer.getAddress()); await expect(() => billBroker.redeem(lpAmtFP("100"))).to.changeTokenBalance( diff --git a/spot-vaults/test/BillBroker_swap.ts b/spot-vaults/test/BillBroker_swap.ts index d22bca2d..91224688 100644 --- a/spot-vaults/test/BillBroker_swap.ts +++ b/spot-vaults/test/BillBroker_swap.ts @@ -2,7 +2,7 @@ import { ethers, upgrades } from "hardhat"; import { Contract } from "ethers"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { expect } from "chai"; -import { DMock, usdFP, perpFP, priceFP, percentageFP } from "./helpers"; +import { DMock, usdFP, perpFP, priceFP, percFP } from "./helpers"; async function updateFees(billBroker: Contract, fees: any) { const currentFees = await billBroker.fees(); @@ -10,11 +10,11 @@ async function updateFees(billBroker: Contract, fees: any) { ...{ mintFeePerc: currentFees[0], burnFeePerc: currentFees[1], - perpToUSDSwapFeePercs: { + perpToUSDSwapFeeFactors: { lower: currentFees[2][0], upper: currentFees[2][1], }, - usdToPerpSwapFeePercs: { + usdToPerpSwapFeeFactors: { lower: currentFees[3][0], upper: currentFees[3][1], }, @@ -28,28 +28,26 @@ async function checkUSDToPerpSwapAmt( billBroker: Contract, usdAmtIn: BigInt, reserveState: any, - amoutsOut: any, + returnVals: any, ) { const r = await billBroker[ "computeUSDToPerpSwapAmt(uint256,(uint256,uint256,uint256,uint256))" ](usdAmtIn, reserveState); - expect(r[0]).to.eq(amoutsOut[0]); - expect(r[1]).to.eq(amoutsOut[1]); - expect(r[2]).to.eq(amoutsOut[2]); + expect(r[0]).to.eq(returnVals[0]); + expect(r[1]).to.eq(returnVals[1]); } -async function checkPerpTpUSDSwapAmt( +async function checkPerpToUSDSwapAmt( billBroker: Contract, perpAmtIn: BigInt, reserveState: any, - amoutsOut: any, + returnVals: any, ) { const r = await billBroker[ "computePerpToUSDSwapAmt(uint256,(uint256,uint256,uint256,uint256))" ](perpAmtIn, reserveState); - expect(r[0]).to.eq(amoutsOut[0]); - expect(r[1]).to.eq(amoutsOut[1]); - expect(r[2]).to.eq(amoutsOut[2]); + expect(r[0]).to.eq(returnVals[0]); + expect(r[1]).to.eq(returnVals[1]); } async function reserveState(billBroker: Contract) { @@ -77,16 +75,16 @@ describe("BillBroker", function () { await usd.init("USD token", "usd", 6); const perp = await Token.deploy(); await perp.init("Perp token", "perp", 9); - const pricingStrategy = new DMock("SpotAppraiser"); - await pricingStrategy.deploy(); - await pricingStrategy.mockMethod("decimals()", [18]); - await pricingStrategy.mockMethod("perpPrice()", [priceFP("1.15"), true]); - await pricingStrategy.mockMethod("usdPrice()", [priceFP("1"), true]); + const oracle = new DMock("IPerpPricer"); + await oracle.deploy(); + await oracle.mockMethod("decimals()", [18]); + await oracle.mockMethod("perpFmvUsdPrice()", [priceFP("1.15"), true]); + await oracle.mockMethod("usdPrice()", [priceFP("1"), true]); const BillBroker = await ethers.getContractFactory("BillBroker"); const billBroker = await upgrades.deployProxy( BillBroker.connect(deployer), - ["BillBroker LP", "LP token", usd.target, perp.target, pricingStrategy.target], + ["BillBroker LP", "LP token", usd.target, perp.target, oracle.target], { initializer: "init(string,string,address,address,address)", }, @@ -94,19 +92,19 @@ describe("BillBroker", function () { await updateFees(billBroker, { mintFeePerc: 0n, burnFeePerc: 0n, - perpToUSDSwapFeePercs: { - lower: 0n, - upper: 0n, + perpToUSDSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, - usdToPerpSwapFeePercs: { - lower: 0n, - upper: 0n, + usdToPerpSwapFeeFactors: { + lower: percFP("1"), + upper: percFP("1"), }, protocolSwapSharePerc: 0n, }); await billBroker.updateARBounds( - [percentageFP("0.9"), percentageFP("1.1")], - [percentageFP("0.75"), percentageFP("1.25")], + [percFP("0.9"), percFP("1.1")], + [percFP("0.75"), percFP("1.25")], ); await usd.mint(billBroker.target, usdFP("115000")); @@ -122,7 +120,7 @@ describe("BillBroker", function () { expect(r.usdPrice).to.eq(priceFP("1")); expect(r.perpPrice).to.eq(priceFP("1.15")); - return { deployer, feeCollector, usd, perp, pricingStrategy, billBroker }; + return { deployer, feeCollector, usd, perp, oracle, billBroker }; } describe("#computeUSDToPerpSwapAmt", function () { @@ -132,7 +130,7 @@ describe("BillBroker", function () { billBroker, usdFP("115"), [usdFP("115000"), perpFP("100000"), priceFP("1"), priceFP("1.15")], - [perpFP("100"), 0n, 0n], + [perpFP("100"), 0n], ); }); @@ -142,7 +140,7 @@ describe("BillBroker", function () { billBroker, usdFP("100"), [usdFP("110000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [perpFP("100"), 0n, 0n], + [perpFP("100"), 0n], ); }); @@ -152,7 +150,7 @@ describe("BillBroker", function () { billBroker, usdFP("11111"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [perpFP("11111"), 0n, 0n], + [perpFP("11111"), 0n], ); }); @@ -162,7 +160,8 @@ describe("BillBroker", function () { billBroker, usdFP("11112"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [0n, 0n, 0n], + + [0n, 0n], ); }); @@ -172,7 +171,7 @@ describe("BillBroker", function () { billBroker, usdFP("100"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("0.9")], - [perpFP("111.111111"), 0n, 0n], + [perpFP("111.111111"), 0n], ); }); @@ -180,80 +179,104 @@ describe("BillBroker", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await checkUSDToPerpSwapAmt( billBroker, usdFP("115"), [usdFP("115000"), perpFP("100000"), priceFP("1"), priceFP("1.15")], - [perpFP("95"), perpFP("5"), 0n], + [perpFP("95"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await checkUSDToPerpSwapAmt( billBroker, usdFP("100"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [perpFP("95"), perpFP("5"), 0n], + [perpFP("95"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await checkUSDToPerpSwapAmt( billBroker, usdFP("100"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("0.9")], - [perpFP("101.460470381"), perpFP("9.650640619"), 0n], + [perpFP("104.190527093"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await checkUSDToPerpSwapAmt( billBroker, usdFP("10000"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [perpFP("8491.666666667"), perpFP("1508.333333333"), 0n], + [perpFP("9163.888888888"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await checkUSDToPerpSwapAmt( billBroker, usdFP("20000"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [0n, 0n, 0n], + [0n, 0n], + ); + }); + + it("should return the perp amount and fees", async function () { + const { billBroker } = await loadFixture(setupContracts); + await updateFees(billBroker, { + perpToUSDSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.1"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), + }, + }); + await billBroker.updateARBounds( + [percFP("0.25"), percFP("4")], + [percFP("0.01"), percFP("100")], + ); + await checkUSDToPerpSwapAmt( + billBroker, + usdFP("10000"), + [usdFP("1000"), perpFP("100000"), priceFP("1"), priceFP("1")], + [perpFP("10649.305555555"), 0n], ); }); }); @@ -262,17 +285,17 @@ describe("BillBroker", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await checkUSDToPerpSwapAmt( billBroker, usdFP("115"), [usdFP("115000"), perpFP("100000"), priceFP("1"), priceFP("1.15")], - [perpFP("95"), perpFP("4.5"), perpFP("0.5")], + [perpFP("95"), perpFP("0.5")], ); }); }); @@ -281,7 +304,7 @@ describe("BillBroker", function () { it("should revert", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await usd.approve(billBroker.target, usdFP("115000")); await billBroker.swapUSDForPerps(usdFP("115000"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); @@ -298,7 +321,7 @@ describe("BillBroker", function () { it("should return the swap amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await perp.approve(billBroker.target, perpFP("100000")); await billBroker.swapPerpsForUSD(perpFP("100000"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); @@ -307,7 +330,7 @@ describe("BillBroker", function () { billBroker, usdFP("100"), [0n, perpFP("100000"), priceFP("1"), priceFP("1")], - [perpFP("100"), 0n, 0n], + [perpFP("100"), 0n], ); }); }); @@ -316,37 +339,37 @@ describe("BillBroker", function () { describe("#computePerpToUSDSwapAmt", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("115000"), perpFP("100000"), priceFP("1"), priceFP("1.15")], - [usdFP("115"), 0n, 0n], + [usdFP("115"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("110000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [usdFP("100"), 0n, 0n], + [usdFP("100"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("14285"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [usdFP("14285"), 0n, 0n], + [usdFP("14285"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("14286"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], @@ -356,11 +379,11 @@ describe("BillBroker", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("0.9")], - [usdFP("90"), 0n, 0n], + [usdFP("90"), 0n], ); }); @@ -368,80 +391,104 @@ describe("BillBroker", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("115000"), perpFP("100000"), priceFP("1"), priceFP("1.15")], - [usdFP("103.5"), usdFP("11.5"), 0n], + [usdFP("103.5"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("110000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [usdFP("90"), usdFP("10"), 0n], + [usdFP("90"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("14285"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [usdFP("11142.474991"), usdFP("3142.525009"), 0n], + [usdFP("12427.993747"), 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("14286"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [0n, 0n, 0n], + [0n, 0n], ); }); it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("100000"), perpFP("100000"), priceFP("1"), priceFP("0.9")], - [usdFP("81"), usdFP("9"), 0n], + [usdFP("81.603396"), 0n], + ); + }); + + it("should return the perp amount and fees", async function () { + const { billBroker } = await loadFixture(setupContracts); + await updateFees(billBroker, { + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), + }, + usdToPerpSwapFeeFactors: { + lower: percFP("1.025"), + upper: percFP("1.2"), + }, + }); + await billBroker.updateARBounds( + [percFP("0.25"), percFP("4")], + [percFP("0.01"), percFP("100")], + ); + await checkPerpToUSDSwapAmt( + billBroker, + perpFP("50000"), + [usdFP("100000"), perpFP("1000"), priceFP("1"), priceFP("1")], + [usdFP("52271.287128"), 0n], ); }); }); @@ -450,17 +497,17 @@ describe("BillBroker", function () { it("should return the perp amount and fees", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("110000"), perpFP("100000"), priceFP("1"), priceFP("1")], - [usdFP("90"), usdFP("9"), usdFP("1")], + [usdFP("90"), usdFP("1")], ); }); }); @@ -468,16 +515,16 @@ describe("BillBroker", function () { describe("when the pool has only usd", function () { it("should return the swap amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await usd.approve(billBroker.target, usdFP("115000")); await billBroker.swapUSDForPerps(usdFP("115000"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); - await checkPerpTpUSDSwapAmt( + await checkPerpToUSDSwapAmt( billBroker, perpFP("100"), [usdFP("100000"), 0n, priceFP("1"), priceFP("1")], - [usdFP("100"), 0n, 0n], + [usdFP("100"), 0n], ); }); }); @@ -485,7 +532,7 @@ describe("BillBroker", function () { describe("when the pool has only perps", function () { it("should return the swap amount", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await perp.approve(billBroker.target, perpFP("100000")); await billBroker.swapPerpsForUSD(perpFP("100000"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); @@ -529,15 +576,15 @@ describe("BillBroker", function () { describe("when oracle price is unreliable", function () { it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("perpPrice()", [0n, false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("perpFmvUsdPrice()", [0n, false]); await expect( billBroker.swapUSDForPerps(usdFP("115"), perpFP("100")), ).to.be.revertedWithCustomError(billBroker, "UnreliablePrice"); }); it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("usdPrice()", [0n, false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("usdPrice()", [0n, false]); await expect( billBroker.swapUSDForPerps(usdFP("115"), perpFP("100")), ).to.be.revertedWithCustomError(billBroker, "UnreliablePrice"); @@ -559,9 +606,9 @@ describe("BillBroker", function () { }); it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapUSDForPerps(usdFP("115"), perpFP("100")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1.002002002002002002")); + expect(await assetRatio(billBroker)).to.eq(percFP("1.002002002002002002")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); @@ -584,9 +631,9 @@ describe("BillBroker", function () { it("should transfer usd from the user", async function () { const { billBroker, deployer, usd } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await expect(() => @@ -596,9 +643,9 @@ describe("BillBroker", function () { it("should transfer perps to the user", async function () { const { billBroker, deployer, perp } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await expect(() => @@ -608,21 +655,21 @@ describe("BillBroker", function () { it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapUSDForPerps(usdFP("115"), perpFP("95")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1.001951854261548471")); + expect(await assetRatio(billBroker)).to.eq(percFP("1.001951854261548471")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await billBroker.swapUSDForPerps(usdFP("115"), perpFP("95")); @@ -633,9 +680,9 @@ describe("BillBroker", function () { it("should emit SwapUSDForPerps", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); const r = await billBroker.reserveState.staticCall(); @@ -649,11 +696,11 @@ describe("BillBroker", function () { it("should transfer usd from the user", async function () { const { billBroker, deployer, usd } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await expect(() => billBroker.swapUSDForPerps(usdFP("115"), perpFP("95")), @@ -664,11 +711,11 @@ describe("BillBroker", function () { setupContracts, ); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker .connect(deployer) @@ -680,11 +727,11 @@ describe("BillBroker", function () { it("should transfer protocol fee to the owner", async function () { const { billBroker, perp, feeCollector } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker.transferOwnership(await feeCollector.getAddress()); await expect(() => @@ -694,24 +741,24 @@ describe("BillBroker", function () { it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapUSDForPerps(usdFP("115"), perpFP("95")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1.001956868809713276")); + expect(await assetRatio(billBroker)).to.eq(percFP("1.001956868809713276")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker.swapUSDForPerps(usdFP("115"), perpFP("95")); const r = await reserveState(billBroker); @@ -721,11 +768,11 @@ describe("BillBroker", function () { it("should emit SwapUSDForPerps", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); const r = await billBroker.reserveState.staticCall(); await expect(billBroker.swapUSDForPerps(usdFP("115"), perpFP("95"))) @@ -738,9 +785,9 @@ describe("BillBroker", function () { it("should transfer usd from the user", async function () { const { billBroker, deployer, usd } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await expect(() => @@ -750,9 +797,9 @@ describe("BillBroker", function () { it("should transfer perps to the user", async function () { const { billBroker, deployer, perp } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await expect(() => @@ -763,21 +810,21 @@ describe("BillBroker", function () { it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapUSDForPerps(usdFP("3795"), perpFP("3130")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1.066432664016930779")); + expect(await assetRatio(billBroker)).to.eq(percFP("1.066432664016930779")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await billBroker.swapUSDForPerps(usdFP("3795"), perpFP("3130")); @@ -788,9 +835,9 @@ describe("BillBroker", function () { it("should emit SwapUSDForPerps", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); const r = await billBroker.reserveState.staticCall(); @@ -804,13 +851,13 @@ describe("BillBroker", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.updateARBounds( - [percentageFP("0.8"), percentageFP("1")], - [percentageFP("0.75"), percentageFP("1.05")], + [percFP("0.8"), percFP("1")], + [percFP("0.75"), percFP("1.05")], ); await updateFees(billBroker, { - usdToPerpSwapFeePercs: { - lower: percentageFP("0.05"), - upper: percentageFP("0.5"), + usdToPerpSwapFeeFactors: { + lower: percFP("1.05"), + upper: percFP("1.2"), }, }); await expect( @@ -822,7 +869,7 @@ describe("BillBroker", function () { describe("when the pool has only usd", function () { it("should revert", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await usd.approve(billBroker.target, usdFP("115000")); await billBroker.swapUSDForPerps(usdFP("115000"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); @@ -836,7 +883,7 @@ describe("BillBroker", function () { describe("when the pool has only perps", function () { it("should execute swap", async function () { const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await perp.approve(billBroker.target, perpFP("100000")); await billBroker.swapPerpsForUSD(perpFP("100000"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); @@ -879,15 +926,15 @@ describe("BillBroker", function () { describe("when oracle price is unreliable", function () { it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("perpPrice()", [0n, false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("perpFmvUsdPrice()", [0n, false]); await expect( billBroker.swapPerpsForUSD(perpFP("115"), usdFP("100")), ).to.be.revertedWithCustomError(billBroker, "UnreliablePrice"); }); it("should revert", async function () { - const { billBroker, pricingStrategy } = await loadFixture(setupContracts); - await pricingStrategy.mockMethod("usdPrice()", [0n, false]); + const { billBroker, oracle } = await loadFixture(setupContracts); + await oracle.mockMethod("usdPrice()", [0n, false]); await expect( billBroker.swapPerpsForUSD(perpFP("115"), usdFP("100")), ).to.be.revertedWithCustomError(billBroker, "UnreliablePrice"); @@ -910,9 +957,9 @@ describe("BillBroker", function () { it("should decrease the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapPerpsForUSD(perpFP("100"), usdFP("115")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("0.998001998001998001")); + expect(await assetRatio(billBroker)).to.eq(percFP("0.998001998001998001")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); @@ -934,9 +981,9 @@ describe("BillBroker", function () { it("should transfer perps from the user", async function () { const { billBroker, deployer, perp } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await expect(() => @@ -946,9 +993,9 @@ describe("BillBroker", function () { it("should transfer usd to the user", async function () { const { billBroker, deployer, usd } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await expect(() => @@ -958,21 +1005,21 @@ describe("BillBroker", function () { it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("0.998101898101898101")); + expect(await assetRatio(billBroker)).to.eq(percFP("0.998101898101898101")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103")); @@ -983,9 +1030,9 @@ describe("BillBroker", function () { it("should emit SwapPerpsForUSD", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); const r = await billBroker.reserveState.staticCall(); @@ -999,11 +1046,11 @@ describe("BillBroker", function () { it("should transfer perps from the user", async function () { const { billBroker, deployer, perp } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await expect(() => billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103")), @@ -1014,11 +1061,11 @@ describe("BillBroker", function () { setupContracts, ); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker.transferOwnership(await feeCollector.getAddress()); await expect(() => @@ -1028,11 +1075,11 @@ describe("BillBroker", function () { it("should transfer protocol fee to the owner", async function () { const { billBroker, usd, feeCollector } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker.transferOwnership(await feeCollector.getAddress()); await expect(() => @@ -1042,24 +1089,24 @@ describe("BillBroker", function () { it("should increase the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("0.998091908091908091")); + expect(await assetRatio(billBroker)).to.eq(percFP("0.998091908091908091")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); await billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103")); const r = await reserveState(billBroker); @@ -1069,11 +1116,11 @@ describe("BillBroker", function () { it("should emit SwapPerpsForUSD", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); const r = await billBroker.reserveState.staticCall(); await expect(billBroker.swapPerpsForUSD(perpFP("100"), usdFP("103"))) @@ -1086,9 +1133,9 @@ describe("BillBroker", function () { it("should transfer perps from the user", async function () { const { billBroker, deployer, perp } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await expect(() => @@ -1098,9 +1145,9 @@ describe("BillBroker", function () { it("should transfer usd to the user", async function () { const { billBroker, deployer, usd } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await expect(() => @@ -1110,21 +1157,21 @@ describe("BillBroker", function () { it("should decrease the reserve ar", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); - expect(await assetRatio(billBroker)).to.eq(percentageFP("1")); + expect(await assetRatio(billBroker)).to.eq(percFP("1")); await billBroker.swapPerpsForUSD(perpFP("3600"), usdFP("3700")); - expect(await assetRatio(billBroker)).to.eq(percentageFP("0.933976833976833976")); + expect(await assetRatio(billBroker)).to.eq(percFP("0.933976833976833976")); }); it("should update the reserve", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await billBroker.swapPerpsForUSD(perpFP("3600"), usdFP("3700")); @@ -1138,13 +1185,13 @@ describe("BillBroker", function () { it("should revert", async function () { const { billBroker } = await loadFixture(setupContracts); await billBroker.updateARBounds( - [percentageFP("1"), percentageFP("1.1")], - [percentageFP("0.95"), percentageFP("1.25")], + [percFP("1"), percFP("1.1")], + [percFP("0.95"), percFP("1.25")], ); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, }); await expect( @@ -1154,11 +1201,11 @@ describe("BillBroker", function () { it("should emit SwapPerpsForUSD", async function () { const { billBroker } = await loadFixture(setupContracts); await updateFees(billBroker, { - perpToUSDSwapFeePercs: { - lower: percentageFP("0.1"), - upper: percentageFP("0.5"), + perpToUSDSwapFeeFactors: { + lower: percFP("1.1"), + upper: percFP("1.2"), }, - protocolSwapSharePerc: percentageFP("0.1"), + protocolSwapSharePerc: percFP("0.1"), }); const r = await billBroker.reserveState.staticCall(); await expect(billBroker.swapPerpsForUSD(perpFP("5000"), usdFP("4000"))) @@ -1170,7 +1217,7 @@ describe("BillBroker", function () { describe("when the pool has only usd", function () { it("should execute swap", async function () { const { billBroker, usd, perp, deployer } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await usd.approve(billBroker.target, usdFP("115000")); await billBroker.swapUSDForPerps(usdFP("115000"), 0n); expect(await perp.balanceOf(billBroker.target)).to.eq(0n); @@ -1185,7 +1232,7 @@ describe("BillBroker", function () { describe("when the pool has only perps", function () { it("should revert", async function () { const { billBroker, usd, perp } = await loadFixture(setupContracts); - await billBroker.updateARBounds([0n, ethers.MaxUint256], [0n, ethers.MaxUint256]); + await billBroker.updateARBounds([0n, ethers.MaxInt256], [0n, ethers.MaxInt256]); await perp.approve(billBroker.target, perpFP("100000")); await billBroker.swapPerpsForUSD(perpFP("100000"), 0n); expect(await usd.balanceOf(billBroker.target)).to.eq(0n); diff --git a/spot-vaults/test/LineHelpers.ts b/spot-vaults/test/LineHelpers.ts new file mode 100644 index 00000000..b3ec16d6 --- /dev/null +++ b/spot-vaults/test/LineHelpers.ts @@ -0,0 +1,310 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { Contract } from "ethers"; + +// AI generated +describe("LineHelpers", function () { + let testLineHelpers: Contract; + + // Deploy the test contract before running the suite + before(async () => { + const LineHelpersTester = await ethers.getContractFactory("LineHelpersTester"); + testLineHelpers = await LineHelpersTester.deploy(); + }); + + // + // Helper for constructing the `Line` struct in TypeScript + // + function makeLine(x1: number, y1: number, x2: number, y2: number) { + return { x1, y1, x2, y2 }; + } + + // + // Helper for constructing the `Range` struct in TypeScript + // + function makeRange(lower: number, upper: number) { + return { lower, upper }; + } + + // --------------------------------------------------------------------- + // 1. Tests for `avgY` + // --------------------------------------------------------------------- + describe("avgY", function () { + it("handles zero slope correctly", async () => { + const fn = makeLine(0, 100, 10, 100); // zero slope + const yAvg = await testLineHelpers.testAvgY(fn, 0, 10); + expect(yAvg).to.equal(100); + + // Subrange + const yAvgSub = await testLineHelpers.testAvgY(fn, 2, 5); + expect(yAvgSub).to.equal(100); + }); + + it("handles positive slope", async () => { + // slope = (200 - 100)/(10 - 0) = 10 + const fn = makeLine(0, 100, 10, 200); + // avg from x=0..10 => (100 + 200)/2 = 150 + const yAvg = await testLineHelpers.testAvgY(fn, 0, 10); + expect(yAvg).to.equal(150); + }); + + it("handles negative slope", async () => { + // slope = (50 - 100)/(10 - 0) = -5 + const fn = makeLine(0, 100, 10, 50); + // avg from x=0..10 => (100 + 50)/2 = 75 + const yAvg = await testLineHelpers.testAvgY(fn, 0, 10); + expect(yAvg).to.equal(75); + }); + + it("handles partial subrange", async () => { + // slope = 10 + // from x=2 => y=120, x=5 => y=150 => avg=135 + const fn = makeLine(0, 100, 10, 200); + const yAvg = await testLineHelpers.testAvgY(fn, 2, 5); + expect(yAvg).to.equal(135); + }); + }); + + // --------------------------------------------------------------------- + // 2. Tests for `computeY` + // --------------------------------------------------------------------- + describe("computeY", function () { + it("handles zero slope", async () => { + const fn = makeLine(0, 100, 10, 100); + const yAt5 = await testLineHelpers.testComputeY(fn, 5); + expect(yAt5).to.equal(100); + }); + + it("handles positive slope", async () => { + // slope=10 => line eq: y=10*x + 100 + const fn = makeLine(0, 100, 10, 200); + const yAt5 = await testLineHelpers.testComputeY(fn, 5); + expect(yAt5).to.equal(150); + }); + + it("handles negative slope", async () => { + // slope=-5 => line eq: y=-5*x + 100 + const fn = makeLine(0, 100, 10, 50); + const yAt2 = await testLineHelpers.testComputeY(fn, 2); + expect(yAt2).to.equal(90); + }); + }); + + // --------------------------------------------------------------------- + // 3. Tests for `computePiecewiseAvgY` + // --------------------------------------------------------------------- + describe("computePiecewiseAvgY", function () { + // Reusable lines and ranges in multiple tests + let fn1, fn2, fn3; + let xBreakPt; + + beforeEach(async () => { + fn1 = makeLine(0, 50, 10, 100); + fn2 = makeLine(0, 100, 10, 200); + fn3 = makeLine(0, 200, 10, 300); + xBreakPt = makeRange(2, 8); + }); + + it("reverts when xRange.lower > xRange.upper", async () => { + const xRange = makeRange(10, 5); // invalid + await expect( + testLineHelpers.testComputePiecewiseAvgY(fn1, fn2, fn3, xBreakPt, xRange), + ).to.be.revertedWithCustomError(testLineHelpers, "InvalidRange"); + }); + + it("reverts when xRange straddles from below to above breakpoints", async () => { + // crosses [2..8] from 1..9 + const xRange = makeRange(1, 9); + await expect( + testLineHelpers.testComputePiecewiseAvgY(fn1, fn2, fn3, xBreakPt, xRange), + ).to.be.revertedWithCustomError(testLineHelpers, "UnexpectedRangeDelta"); + }); + + it("uses fn1 entirely when xRange is below xBreakPt.lower", async () => { + // xBreakPt= [2..8], xRange= [0..1] + const localBreak = makeRange(2, 8); + const localRange = makeRange(0, 1); + const localFn1 = makeLine(0, 50, 10, 70); // slope ~ 2/unit + const localFn2 = makeLine(10, 60, 20, 200); + const localFn3 = makeLine(20, 200, 30, 500); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + localFn3, + localBreak, + localRange, + ); + expect(result).to.equal(51); + }); + + it("uses fn3 entirely when xRange is above xBreakPt.upper", async () => { + // xBreakPt= [2..8], xRange= [9..10] + const localBreak = makeRange(2, 8); + const localRange = makeRange(9, 10); + + // fn3 from (8,200) to (10,300) + // y(9)=250, y(10)=300 => avg=275 + const localFn1 = makeLine(0, 0, 10, 0); + const localFn2 = makeLine(10, 0, 20, 100); + const localFn3 = makeLine(8, 200, 10, 300); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + localFn3, + localBreak, + localRange, + ); + expect(result).to.equal(275); + }); + + it("splits range across fn1 & fn2 when straddling xBreakPt.lower", async () => { + // xBreakPt= [2..8], xRange= [1..5] + const localBreak = makeRange(2, 8); + const localRange = makeRange(1, 5); + + // fn1 => (0,10)->(2,30), slope=10 + // x=1 => y=20, x=2 => y=30 => avg=25 + // fn2 => (2,30)->(8,90), slope=10 + // x=2 => y=30, x=5 => y=60 => avg=45 + // Weighted sum => (25*1) + (45*3)=160 => /4=40 + const localFn1 = makeLine(0, 10, 2, 30); + const localFn2 = makeLine(2, 30, 8, 90); + const localFn3 = makeLine(8, 90, 10, 100); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + localFn3, + localBreak, + localRange, + ); + expect(result).to.equal(40); + }); + + it("splits range across fn2 & fn3 when straddling xBreakPt.upper", async () => { + // xBreakPt= [2..8], xRange= [5..9] + const localBreak = makeRange(2, 8); + const localRange = makeRange(5, 9); + + // fn2 => (2,30)->(8,90), slope=10 + // x=5 => y=60, x=8 => y=90 => avg=75 + // fn3 => (8,90)->(10,110), slope=10 + // x=8 => y=90, x=9 => y=100 => avg=95 + // Weighted sum => (75*3)+(95*1)=320 => /4=80 + const localFn1 = makeLine(0, 10, 2, 30); + const localFn2 = makeLine(2, 30, 8, 90); + const localFn3 = makeLine(8, 90, 10, 110); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + localFn3, + localBreak, + localRange, + ); + expect(result).to.equal(80); + }); + + it("uses only fn2 when xRange is fully within breakpoints", async () => { + // xBreakPt= [2..8], xRange= [3..7] + // fn2 => (2,20)->(8,80), slope=10 + // x=3 => y=30, x=7 => y=70 => avg=50 + const localBreak = makeRange(2, 8); + const localRange = makeRange(3, 7); + + const localFn1 = makeLine(0, 10, 2, 20); + const localFn2 = makeLine(2, 20, 8, 80); + const localFn3 = makeLine(8, 80, 10, 100); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + localFn3, + localBreak, + localRange, + ); + expect(result).to.equal(50); + }); + + it("handles zero-length xRange exactly at xBreakPt.lower", async () => { + // xRange= [2..2] => a single x-value + // Expect to take fn1 vs fn2? + // Typically, a single x==2 is the boundary => By definition, + // if `upper <= breakPt.lower` => we are in fn1 + // OR if `lower >= breakPt.lower` => we might be in fn2. + // This might require clarity in your design or the function. + // For demonstration, let's assume we define: + // if x == bpl => treat as fn2 (since "below" is strictly < bpl). + const localRange = makeRange(2, 2); + // We'll set the lines so we can easily compute y(2). + const localFn1 = makeLine(0, 10, 2, 30); // y(2)=30 + const localFn2 = makeLine(2, 30, 8, 90); // y(2)=30 + // We'll see which one the code picks based on your piecewise logic + // For a zero-length range, the "average" is just y(2). + + const result = await testLineHelpers.testComputePiecewiseAvgY( + localFn1, + localFn2, + fn3, + xBreakPt, + localRange, + ); + // Depending on your code logic: + // If your code lumps x=breakPt.lower in fn1, expect 30 + // If lumps it in fn2, also 30 in this example (coincidentally the same). + // If you want to ensure it's definitely fn2, you could change lines: + // localFn2 = makeLine(2, 50, 8, 90) => y(2)=50 + // Then check if result==50 => means it's definitely fn2. + expect(result).to.equal(30); + }); + + it("handles zero-length xRange exactly at xBreakPt.upper", async () => { + // xBreakPt= [2..8], xRange= [8..8] + // Single point at x=8 + // By your design, x=8 could be considered "upper edge" of fn2 or "start" of fn3. + const localRange = makeRange(8, 8); + + // Distinguish the lines so we can confirm which is used + const localFn2 = makeLine(2, 20, 8, 80); // y(8)=80 + const localFn3 = makeLine(8, 999, 10, 1000); // y(8)=999 + + const result = await testLineHelpers.testComputePiecewiseAvgY( + fn1, + localFn2, + localFn3, + xBreakPt, + localRange, + ); + // Depending on how your piecewise function is coded: + // - If x=breakPt.upper is still "within" fn2 => expect 80 + // - If your code lumps it with fn3 => expect 999 + // In *your* logic, it looks like "if (xRange.lower <= bpu && xRange.upper > bpu)" + // is the condition for partial in fn2/fn3. + // But here, 8..8 is exactly <=bpu and not >bpu => might remain in fn2 + // So I'd expect 80 given the code snippet above. + expect(result).to.equal(80); + }); + + it("uses only fn2 when xRange = xBreakPt exactly", async () => { + // xRange= [2..8], which is exactly the break range + // Should use fn2 entirely, no partial + const localRange = makeRange(2, 8); + // We'll define fn2 so we can test the integral average from 2..8 + // Let's pick slope=10 again => + // y(2)=20, y(8)=80 => average => (20+80)/2=50 + const localFn2 = makeLine(2, 20, 8, 80); + + const result = await testLineHelpers.testComputePiecewiseAvgY( + fn1, + localFn2, + fn3, + xBreakPt, + localRange, + ); + // If the code lumps [2..8] wholly into fn2, we get 50 + expect(result).to.equal(50); + }); + }); +}); diff --git a/spot-vaults/test/SpotAppraiser.ts b/spot-vaults/test/SpotAppraiser.ts deleted file mode 100644 index 80f1e85b..00000000 --- a/spot-vaults/test/SpotAppraiser.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { ethers } from "hardhat"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import { expect } from "chai"; -import { oracleAnsFP, perpFP, percentageFP, priceFP, DMock } from "./helpers"; - -const nowTS = () => parseInt(Date.now() / 1000); - -describe("SpotAppraiser", function () { - async function setupContracts() { - const accounts = await ethers.getSigners(); - const deployer = accounts[0]; - - const amplTargetOracle = new DMock("MedianOracle"); - await amplTargetOracle.deploy(); - await amplTargetOracle.mockMethod("getData()", [priceFP("1.15"), true]); - await amplTargetOracle.mockMethod("DECIMALS()", [18]); - - const policy = new DMock("UFragmentsPolicy"); - await policy.deploy(); - await policy.mockMethod("cpiOracle()", [amplTargetOracle.target]); - - const ampl = new DMock("UFragments"); - await ampl.deploy(); - await ampl.mockMethod("decimals()", [9]); - await ampl.mockMethod("monetaryPolicy()", [policy.target]); - - const bond = new DMock("BondController"); - await bond.deploy(); - await bond.mockMethod("isMature()", [false]); - await bond.mockMethod("trancheCount()", [2]); - await bond.mockMethod("totalDebt()", [perpFP("500000")]); - await ampl.mockCall("balanceOf(address)", [bond.target], [perpFP("500000")]); - - const tranche = new DMock("Tranche"); - await tranche.deploy(); - await tranche.mockMethod("bond()", [bond.target]); - await tranche.mockMethod("totalSupply()", [perpFP("100000")]); - await bond.mockCall("tranches(uint256)", [0], [tranche.target, 200]); - await bond.mockCall("tranches(uint256)", [1], [ethers.ZeroAddress, 800]); - - const spot = new DMock("PerpetualTranche"); - await spot.deploy(); - await spot.mockMethod("underlying()", [ampl.target]); - await spot.mockMethod("getTVL()", [perpFP("1000000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - await spot.mockMethod("deviationRatio()", [oracleAnsFP("1.5")]); - await spot.mockMethod("getReserveCount()", [2]); - await spot.mockCall("getReserveAt(uint256)", [0], [ampl.target]); - await spot.mockCall("getReserveAt(uint256)", [1], [tranche.target]); - await ampl.mockCall("balanceOf(address)", [spot.target], [perpFP("1000")]); - - const usdPriceOrcle = new DMock("IChainlinkOracle"); - await usdPriceOrcle.deploy(); - await usdPriceOrcle.mockMethod("decimals()", [8]); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1"), - 0, - nowTS(), - 0, - ]); - - const SpotAppraiser = await ethers.getContractFactory("SpotAppraiser"); - const strategy = await SpotAppraiser.deploy( - spot.target, - usdPriceOrcle.target, - amplTargetOracle.target, - ); - return { - deployer, - ampl, - spot, - usdPriceOrcle, - amplTargetOracle, - bond, - tranche, - strategy, - }; - } - - describe("init", function () { - it("should initial params", async function () { - const { deployer, strategy, ampl, spot, usdPriceOrcle, amplTargetOracle } = - await loadFixture(setupContracts); - expect(await strategy.AMPL()).to.eq(ampl.target); - expect(await strategy.SPOT()).to.eq(spot.target); - expect(await strategy.USD_ORACLE()).to.eq(usdPriceOrcle.target); - expect(await strategy.AMPL_CPI_ORACLE()).to.eq(amplTargetOracle.target); - expect(await strategy.AMPL_DUST_AMT()).to.eq(perpFP("25000")); - expect(await strategy.minSPOTDR()).to.eq(percentageFP("0.8")); - expect(await strategy.minSeniorCDR()).to.eq(percentageFP("1.1")); - expect(await strategy.owner()).to.eq(await deployer.getAddress()); - expect(await strategy.decimals()).to.eq(18); - }); - }); - - describe("#updateMinSPOTDR", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - const { strategy } = await loadFixture(setupContracts); - await strategy.renounceOwnership(); - await expect(strategy.updateMinSPOTDR(percentageFP("1.15"))).to.be.revertedWith( - "Ownable: caller is not the owner", - ); - }); - }); - - describe("when triggered by owner", function () { - it("should update value", async function () { - const { strategy } = await loadFixture(setupContracts); - await strategy.updateMinSPOTDR(percentageFP("1.15")); - expect(await strategy.minSPOTDR()).to.eq(percentageFP("1.15")); - }); - }); - }); - - describe("#updateMinPerpCollateralCDR", function () { - describe("when triggered by non-owner", function () { - it("should revert", async function () { - const { strategy } = await loadFixture(setupContracts); - await strategy.renounceOwnership(); - await expect( - strategy.updateMinPerpCollateralCDR(percentageFP("1.25")), - ).to.be.revertedWith("Ownable: caller is not the owner"); - }); - }); - - describe("when cdr is invalid", function () { - it("should revert", async function () { - const { strategy } = await loadFixture(setupContracts); - await expect( - strategy.updateMinPerpCollateralCDR(percentageFP("0.9")), - ).to.be.revertedWithCustomError(strategy, "InvalidSeniorCDRBound"); - }); - }); - - describe("when triggered by owner", function () { - it("should update value", async function () { - const { strategy } = await loadFixture(setupContracts); - await strategy.updateMinPerpCollateralCDR(percentageFP("1.25")); - expect(await strategy.minSeniorCDR()).to.eq(percentageFP("1.25")); - }); - }); - }); - - describe("#usdPrice", function () { - describe("when data is stale", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1"), - 0, - nowTS() - 50 * 3600, - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when oracle price is below thresh", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("0.98"), - 0, - nowTS(), - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when oracle price is above thresh", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1.02"), - 0, - nowTS(), - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - it("should return price", async function () { - const { strategy } = await loadFixture(setupContracts); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(true); - }); - }); - - describe("#perpPrice", function () { - describe("when AMPL target data is invalid", function () { - it("should return invalid", async function () { - const { strategy, amplTargetOracle } = await loadFixture(setupContracts); - await amplTargetOracle.mockMethod("getData()", [priceFP("1.2"), false]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.2")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when balancer DR is too low", function () { - it("should return invalid", async function () { - const { strategy, spot } = await loadFixture(setupContracts); - await spot.mockMethod("deviationRatio()", [oracleAnsFP("0.79999")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when spot senior cdr is too low", function () { - it("should return invalid", async function () { - const { strategy, ampl, bond } = await loadFixture(setupContracts); - await ampl.mockCall("balanceOf(address)", [bond.target], [perpFP("109999")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(false); - }); - it("should return invalid", async function () { - const { strategy, bond } = await loadFixture(setupContracts); - await bond.mockMethod("isMature()", [true]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when spot has mature AMPL", function () { - it("should return invalid", async function () { - const { strategy, ampl, spot } = await loadFixture(setupContracts); - await ampl.mockCall("balanceOf(address)", [spot.target], [perpFP("25001")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(false); - }); - }); - - it("should return price", async function () { - const { strategy } = await loadFixture(setupContracts); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(true); - }); - - describe("when debasement/enrichment multiplier is not 1", function () { - it("should return price", async function () { - const { strategy, spot } = await loadFixture(setupContracts); - await spot.mockMethod("getTVL()", [perpFP("1500000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.725")); - expect(p[1]).to.eq(true); - }); - it("should return price", async function () { - const { strategy, spot } = await loadFixture(setupContracts); - await spot.mockMethod("getTVL()", [perpFP("900000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.035")); - expect(p[1]).to.eq(true); - }); - }); - }); -}); diff --git a/spot-vaults/test/SpotCDRPricer.ts b/spot-vaults/test/SpotCDRPricer.ts deleted file mode 100644 index b3095ee7..00000000 --- a/spot-vaults/test/SpotCDRPricer.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { ethers } from "hardhat"; -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; -import { expect } from "chai"; -import { oracleAnsFP, perpFP, priceFP, DMock } from "./helpers"; - -const nowTS = () => parseInt(Date.now() / 1000); - -describe("SpotCDRPricer", function () { - async function setupContracts() { - const accounts = await ethers.getSigners(); - const deployer = accounts[0]; - - const amplTargetOracle = new DMock("MedianOracle"); - await amplTargetOracle.deploy(); - await amplTargetOracle.mockMethod("getData()", [priceFP("1.15"), true]); - await amplTargetOracle.mockMethod("DECIMALS()", [18]); - - const policy = new DMock("UFragmentsPolicy"); - await policy.deploy(); - await policy.mockMethod("cpiOracle()", [amplTargetOracle.target]); - - const ampl = new DMock("UFragments"); - await ampl.deploy(); - await ampl.mockMethod("decimals()", [9]); - await ampl.mockMethod("monetaryPolicy()", [policy.target]); - - const spot = new DMock("PerpetualTranche"); - await spot.deploy(); - await spot.mockMethod("underlying()", [ampl.target]); - await spot.mockMethod("getTVL()", [perpFP("1000000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - - const usdPriceOrcle = new DMock("IChainlinkOracle"); - await usdPriceOrcle.deploy(); - await usdPriceOrcle.mockMethod("decimals()", [8]); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1"), - 0, - nowTS(), - 0, - ]); - - const SpotCDRPricer = await ethers.getContractFactory("SpotCDRPricer"); - const strategy = await SpotCDRPricer.deploy( - spot.target, - usdPriceOrcle.target, - amplTargetOracle.target, - ); - return { - deployer, - ampl, - spot, - usdPriceOrcle, - amplTargetOracle, - strategy, - }; - } - - describe("init", function () { - it("should initial params", async function () { - const { strategy, ampl, spot, usdPriceOrcle, amplTargetOracle } = await loadFixture( - setupContracts, - ); - expect(await strategy.AMPL()).to.eq(ampl.target); - expect(await strategy.SPOT()).to.eq(spot.target); - expect(await strategy.USD_ORACLE()).to.eq(usdPriceOrcle.target); - expect(await strategy.AMPL_CPI_ORACLE()).to.eq(amplTargetOracle.target); - expect(await strategy.decimals()).to.eq(18); - }); - }); - - describe("#usdPrice", function () { - describe("when data is stale", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1"), - 0, - nowTS() - 50 * 3600, - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when oracle price is below thresh", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("0.98"), - 0, - nowTS(), - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - describe("when oracle price is above thresh", function () { - it("should return invalid", async function () { - const { strategy, usdPriceOrcle } = await loadFixture(setupContracts); - await usdPriceOrcle.mockMethod("latestRoundData()", [ - 0, - oracleAnsFP("1.02"), - 0, - nowTS(), - 0, - ]); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(false); - }); - }); - - it("should return price", async function () { - const { strategy } = await loadFixture(setupContracts); - const p = await strategy.usdPrice(); - expect(p[0]).to.eq(priceFP("1")); - expect(p[1]).to.eq(true); - }); - }); - - describe("#perpPrice", function () { - describe("when AMPL target data is invalid", function () { - it("should return invalid", async function () { - const { strategy, amplTargetOracle } = await loadFixture(setupContracts); - await amplTargetOracle.mockMethod("getData()", [priceFP("1.2"), false]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.2")); - expect(p[1]).to.eq(false); - }); - }); - - it("should return price", async function () { - const { strategy } = await loadFixture(setupContracts); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.15")); - expect(p[1]).to.eq(true); - }); - - describe("when debasement/enrichment multiplier is not 1", function () { - it("should return price", async function () { - const { strategy, spot } = await loadFixture(setupContracts); - await spot.mockMethod("getTVL()", [perpFP("1500000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.725")); - expect(p[1]).to.eq(true); - }); - it("should return price", async function () { - const { strategy, spot } = await loadFixture(setupContracts); - await spot.mockMethod("getTVL()", [perpFP("900000")]); - await spot.mockMethod("totalSupply()", [perpFP("1000000")]); - const p = await strategy.perpPrice.staticCall(); - expect(p[0]).to.eq(priceFP("1.035")); - expect(p[1]).to.eq(true); - }); - }); - }); -}); diff --git a/spot-vaults/test/SpotPricer.ts b/spot-vaults/test/SpotPricer.ts new file mode 100644 index 00000000..e1f3f1b8 --- /dev/null +++ b/spot-vaults/test/SpotPricer.ts @@ -0,0 +1,379 @@ +import { ethers } from "hardhat"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { expect } from "chai"; +import { + amplOracleFP, + usdOracleFP, + ethOracleFP, + perpFP, + percFP, + priceFP, + wamplFP, + amplFP, + drFP, + DMock, +} from "./helpers"; + +const nowTS = () => parseInt(Date.now() / 1000); + +describe("SpotPricer", function () { + async function setupContracts() { + const amplPolicy = new DMock("IAmpleforth"); + await amplPolicy.deploy(); + await amplPolicy.mockMethod("getTargetRate()", [priceFP("1.15"), true]); + + const ampl = new DMock("UFragments"); + await ampl.deploy(); + await ampl.mockMethod("decimals()", [9]); + await ampl.mockMethod("monetaryPolicy()", [amplPolicy.target]); + + const usdcPriceOrcle = new DMock("IChainlinkOracle"); + await usdcPriceOrcle.deploy(); + await usdcPriceOrcle.mockMethod("decimals()", [8]); + await usdcPriceOrcle.mockMethod("latestRoundData()", [ + 0, + usdOracleFP("1"), + 0, + nowTS(), + 0, + ]); + + const ethPriceOrcle = new DMock("IChainlinkOracle"); + await ethPriceOrcle.deploy(); + await ethPriceOrcle.mockMethod("decimals()", [18]); + await ethPriceOrcle.mockMethod("latestRoundData()", [ + 0, + ethOracleFP("2357.76"), + 0, + nowTS(), + 0, + ]); + + const usdc = new DMock("contracts/_interfaces/external/IERC20.sol:IERC20"); + await usdc.deploy(); + + const wampl = new DMock("IWAMPL"); + await wampl.deploy(); + await wampl.mockCall( + "wrapperToUnderlying(uint256)", + [wamplFP("1")], + [amplFP("7.692284616")], + ); + + const bond = new DMock( + "contracts/_interfaces/external/IBondController.sol:IBondController", + ); + await bond.deploy(); + await bond.mockMethod("collateralBalance()", [perpFP("2000")]); + + const tranche = new DMock("Tranche"); + await tranche.deploy(); + await tranche.mockMethod("bond()", [bond.target]); + + const feePolicy = new DMock("IPerpFeePolicy"); + await feePolicy.deploy(); + await feePolicy.mockMethod("decimals()", [8]); + await feePolicy.mockMethod("deviationRatio()", [drFP("1")]); + await feePolicy.mockMethod("computePerpRolloverFeePerc(uint256)", [0]); + + const spot = new DMock("PerpetualTranche"); + await spot.deploy(); + await spot.mockMethod("feePolicy()", [feePolicy.target]); + await spot.mockMethod("underlying()", [ampl.target]); + await spot.mockMethod("getTVL()", [perpFP("1000")]); + await spot.mockMethod("totalSupply()", [perpFP("1000")]); + await spot.mockMethod("getReserveCount()", [2]); + await spot.mockCall("getReserveAt(uint256)", [0], [ampl.target]); + await spot.mockCall("getReserveTokenBalance(address)", [ampl.target], ["0"]); + await spot.mockCall("getReserveAt(uint256)", [1], [tranche.target]); + await spot.mockCall( + "getReserveTokenBalance(address)", + [tranche.target], + [perpFP("1000")], + ); + await spot.mockCall( + "getReserveTokenValue(address)", + [tranche.target], + [perpFP("1000")], + ); + + const wamplPool = new DMock("IUniswapV3Pool"); + await wamplPool.deploy(); + await wamplPool.mockMethod("token1()", [wampl.target]); + await wamplPool.mockMethod("observe(uint32[])", [ + ["376921685400", "377121673968"], + ["5338479444003340079488911551", "5338479669430834262798687400"], + ]); + + const spotPool = new DMock("IUniswapV3Pool"); + await spotPool.deploy(); + await spotPool.mockMethod("token0()", [usdc.target]); + await spotPool.mockMethod("token1()", [spot.target]); + await spotPool.mockMethod("observe(uint32[])", [ + ["3780978019944", "3781218388344"], + [ + "15033345577239143106349258268248842184594399522", + "15033345577239143129748458314415242759127803748", + ], + ]); + + const SpotPricer = await ethers.getContractFactory("SpotPricer"); + const strategy = await SpotPricer.deploy( + wamplPool.target, + spotPool.target, + ethPriceOrcle.target, + usdcPriceOrcle.target, + ); + return { + amplPolicy, + ethPriceOrcle, + usdcPriceOrcle, + usdc, + ampl, + wampl, + spot, + feePolicy, + bond, + tranche, + wamplPool, + spotPool, + strategy, + }; + } + + describe("init", function () { + it("should initial params", async function () { + const { + amplPolicy, + ethPriceOrcle, + usdcPriceOrcle, + usdc, + ampl, + wampl, + spot, + wamplPool, + spotPool, + strategy, + } = await loadFixture(setupContracts); + expect(await strategy.WETH_WAMPL_POOL()).to.eq(wamplPool.target); + expect(await strategy.USDC_SPOT_POOL()).to.eq(spotPool.target); + + expect(await strategy.ETH_ORACLE()).to.eq(ethPriceOrcle.target); + expect(await strategy.USDC_ORACLE()).to.eq(usdcPriceOrcle.target); + expect(await strategy.AMPLEFORTH_POLICY()).to.eq(amplPolicy.target); + + expect(await strategy.WAMPL()).to.eq(wampl.target); + expect(await strategy.USDC()).to.eq(usdc.target); + expect(await strategy.AMPL()).to.eq(ampl.target); + expect(await strategy.SPOT()).to.eq(spot.target); + expect(await strategy.decimals()).to.eq(18); + }); + }); + + describe("#usdPrice", function () { + describe("when data is stale", function () { + it("should return invalid", async function () { + const { strategy, usdcPriceOrcle } = await loadFixture(setupContracts); + await usdcPriceOrcle.mockMethod("latestRoundData()", [ + 0, + usdOracleFP("1"), + 0, + nowTS() - 50 * 3600, + 0, + ]); + const p = await strategy.usdPrice(); + expect(p[0]).to.eq(amplOracleFP("1")); + expect(p[1]).to.eq(false); + }); + }); + + describe("when oracle price is below thresh", function () { + it("should return invalid", async function () { + const { strategy, usdcPriceOrcle } = await loadFixture(setupContracts); + await usdcPriceOrcle.mockMethod("latestRoundData()", [ + 0, + usdOracleFP("0.98"), + 0, + nowTS(), + 0, + ]); + const p = await strategy.usdPrice(); + expect(p[0]).to.eq(amplOracleFP("1")); + expect(p[1]).to.eq(false); + }); + }); + + describe("when oracle price is above thresh", function () { + it("should return invalid", async function () { + const { strategy, usdcPriceOrcle } = await loadFixture(setupContracts); + await usdcPriceOrcle.mockMethod("latestRoundData()", [ + 0, + usdOracleFP("1.02"), + 0, + nowTS(), + 0, + ]); + const p = await strategy.usdPrice(); + expect(p[0]).to.eq(amplOracleFP("1")); + expect(p[1]).to.eq(false); + }); + }); + + it("should return price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.usdPrice(); + expect(p[0]).to.eq(amplOracleFP("1")); + expect(p[1]).to.eq(true); + }); + }); + + describe("#perpFmvUsdPrice", function () { + describe("when AMPL target data is invalid", function () { + it("should return invalid", async function () { + const { strategy, amplPolicy } = await loadFixture(setupContracts); + await amplPolicy.mockMethod("getTargetRate()", [amplOracleFP("1.2"), false]); + const p = await strategy.perpFmvUsdPrice.staticCall(); + expect(p[0]).to.eq(amplOracleFP("1.2")); + expect(p[1]).to.eq(false); + }); + }); + + it("should return price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.perpFmvUsdPrice.staticCall(); + expect(p[0]).to.eq(amplOracleFP("1.15")); + expect(p[1]).to.eq(true); + }); + + describe("when debasement/enrichment multiplier is not 1", function () { + it("should return price", async function () { + const { strategy, spot } = await loadFixture(setupContracts); + await spot.mockMethod("getTVL()", [perpFP("1500000")]); + await spot.mockMethod("totalSupply()", [perpFP("1000000")]); + const p = await strategy.perpFmvUsdPrice.staticCall(); + expect(p[0]).to.eq(amplOracleFP("1.725")); + expect(p[1]).to.eq(true); + }); + it("should return price", async function () { + const { strategy, spot } = await loadFixture(setupContracts); + await spot.mockMethod("getTVL()", [perpFP("900000")]); + await spot.mockMethod("totalSupply()", [perpFP("1000000")]); + const p = await strategy.perpFmvUsdPrice.staticCall(); + expect(p[0]).to.eq(amplOracleFP("1.035")); + expect(p[1]).to.eq(true); + }); + }); + }); + + describe("#perpUsdPrice", function () { + describe("when usdc price is invalid", function () { + it("should return invalid", async function () { + const { strategy, usdcPriceOrcle } = await loadFixture(setupContracts); + await usdcPriceOrcle.mockMethod("latestRoundData()", [ + 0, + usdOracleFP("1"), + 0, + nowTS() - 50 * 3600, + 0, + ]); + const p = await strategy.perpUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("1.260097503535148000")); + expect(p[1]).to.eq(false); + }); + }); + + it("should compute spot usd price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.perpUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("1.260097503535148000")); + expect(p[1]).to.eq(true); + }); + }); + + describe("#underlyingUsdPrice", function () { + describe("when eth price is invalid", function () { + it("should return invalid", async function () { + const { strategy, ethPriceOrcle } = await loadFixture(setupContracts); + await ethPriceOrcle.mockMethod("latestRoundData()", [ + 0, + ethOracleFP("3000"), + 0, + nowTS() - 50 * 3600, + 0, + ]); + const p = await strategy.underlyingUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("1.508668510241881174")); + expect(p[1]).to.eq(false); + }); + }); + + it("should compute ampl price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.underlyingUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("1.185692755569299252")); + expect(p[1]).to.eq(true); + }); + }); + + describe("intermediate prices", function () { + it("should compute eth price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.ethUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("2357.76")); + expect(p[1]).to.eq(true); + }); + + it("should compute wampl price", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.wamplUsdPrice.staticCall(); + expect(p[0]).to.eq(priceFP("9.120686142968368965")); + expect(p[1]).to.eq(true); + }); + + it("should compute spot price deviation", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.spotPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("1.095736959595780869")); + expect(p[1]).to.eq(true); + }); + + it("should compute spot price deviation", async function () { + const { strategy, amplPolicy } = await loadFixture(setupContracts); + await amplPolicy.mockMethod("getTargetRate()", [amplOracleFP("2"), true]); + const p = await strategy.spotPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("0.630048751767574000")); + expect(p[1]).to.eq(true); + }); + + it("should compute spot price deviation", async function () { + const { strategy, amplPolicy } = await loadFixture(setupContracts); + await amplPolicy.mockMethod("getTargetRate()", [amplOracleFP("0"), false]); + const p = await strategy.spotPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("100")); + expect(p[1]).to.eq(false); + }); + + it("should compute ampl price deviation", async function () { + const { strategy } = await loadFixture(setupContracts); + const p = await strategy.amplPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("1.031037178755912393")); + expect(p[1]).to.eq(true); + }); + + it("should compute spot price deviation", async function () { + const { strategy, amplPolicy } = await loadFixture(setupContracts); + await amplPolicy.mockMethod("getTargetRate()", [amplOracleFP("1.5"), true]); + const p = await strategy.amplPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("0.790461837046199501")); + expect(p[1]).to.eq(true); + }); + + it("should compute spot price deviation", async function () { + const { strategy, amplPolicy } = await loadFixture(setupContracts); + await amplPolicy.mockMethod("getTargetRate()", [amplOracleFP("0"), false]); + const p = await strategy.amplPriceDeviation.staticCall(); + expect(p[0]).to.eq(percFP("100")); + expect(p[1]).to.eq(false); + }); + }); +}); diff --git a/spot-vaults/test/UsdcSpotManager.ts b/spot-vaults/test/UsdcSpotManager.ts index e4e437a2..3f38c72a 100644 --- a/spot-vaults/test/UsdcSpotManager.ts +++ b/spot-vaults/test/UsdcSpotManager.ts @@ -17,22 +17,37 @@ describe("UsdcSpotManager", function () { // Deploy mock contracts const mockVault = new DMock("IAlphaProVault"); await mockVault.deploy(); - await mockVault.mockMethod("fullLower()", [-800000]); - await mockVault.mockMethod("fullUpper()", [800000]); - await mockVault.mockMethod("baseLower()", [45000]); - await mockVault.mockMethod("baseUpper()", [55000]); - await mockVault.mockMethod("getTwap()", [67200]); - await mockVault.mockMethod("limitThreshold()", [800000]); const mockPool = new DMock("IUniswapV3Pool"); await mockPool.deploy(); + await mockPool.mockCall( + "positions(bytes32)", + [univ3PositionKey(mockVault.target, -800000, 800000)], + [100000, 0, 0, 0, 0], + ); + await mockPool.mockCall( + "positions(bytes32)", + [univ3PositionKey(mockVault.target, -1000, 1000)], + [0, 0, 0, 0, 0], + ); + await mockPool.mockCall( + "positions(bytes32)", + [univ3PositionKey(mockVault.target, 20000, 40000)], + [50000, 0, 0, 0, 0], + ); + await mockVault.mockMethod("baseLower()", [-1000]); + await mockVault.mockMethod("baseUpper()", [1000]); + await mockVault.mockMethod("fullLower()", [-800000]); + await mockVault.mockMethod("fullUpper()", [800000]); + await mockVault.mockMethod("limitLower()", [20000]); + await mockVault.mockMethod("limitUpper()", [40000]); await mockVault.mockMethod("pool()", [mockPool.target]); + await mockVault.mockMethod("getTotalAmounts()", [usdcFP("500000"), spotFP("500000")]); - const mockAppraiser = new DMock("ISpotPricingStrategy"); - await mockAppraiser.deploy(); - await mockAppraiser.mockMethod("decimals()", [18]); - await mockAppraiser.mockMethod("perpPrice()", [priceFP("1.2"), true]); - await mockAppraiser.mockMethod("usdPrice()", [priceFP("1"), true]); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1.2"), true]); const mockUsdc = new DMock("IERC20Upgradeable"); await mockUsdc.deploy(); @@ -44,13 +59,13 @@ describe("UsdcSpotManager", function () { // Deploy Manager contract const Manager = await ethers.getContractFactory("UsdcSpotManager"); - const manager = await Manager.deploy(mockVault.target, mockAppraiser.target); + const manager = await Manager.deploy(mockVault.target, mockOracle.target); return { owner, addr1, mockVault, - mockAppraiser, + mockOracle, mockUsdc, mockSpot, mockPool, @@ -58,6 +73,56 @@ describe("UsdcSpotManager", function () { }; } + async function stubRebalance(mockVault) { + await mockVault.clearMockMethod("setPeriod(uint32)"); + await mockVault.clearMockMethod("period()"); + await mockVault.mockMethod("rebalance()", []); + } + + async function stubForceRebalance(mockVault) { + await mockVault.mockMethod("period()", [86400]); + await mockVault.mockCall("setPeriod(uint32)", [0], []); + await mockVault.mockCall("setPeriod(uint32)", [86400], []); + await mockVault.mockMethod("rebalance()", []); + } + + async function stubOverweightSpot(mockVault) { + await mockVault.mockMethod("getTwap()", [30001]); + } + + async function stubOverweightUsdc(mockVault) { + await mockVault.mockMethod("getTwap()", [29999]); + } + + async function stubActiveZoneLiq(mockVault, fr, base, limit) { + await mockVault.mockCall("setFullRangeWeight(uint24)", [fr], []); + await mockVault.mockCall("setBaseThreshold(int24)", [base], []); + await mockVault.mockCall("setLimitThreshold(int24)", [limit], []); + } + + async function stubInactiveLiq(mockVault) { + await mockVault.mockCall("setFullRangeWeight(uint24)", [1000000], []); + await mockVault.mockCall("setBaseThreshold(int24)", [48000], []); + await mockVault.mockCall("setLimitThreshold(int24)", [48000], []); + } + + async function stubTrimFullRangeLiq(mockVault, burntLiq) { + await mockVault.mockCall( + "emergencyBurn(int24,int24,uint128)", + [-800000, 800000, burntLiq], + [], + ); + } + + async function stubRemovedLimitRange(mockVault) { + await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); + await mockVault.mockCall( + "emergencyBurn(int24,int24,uint128)", + [20000, 40000, 50000], + [], + ); + } + describe("Initialization", function () { it("should set the correct owner", async function () { const { manager, owner } = await loadFixture(setupContracts); @@ -70,67 +135,114 @@ describe("UsdcSpotManager", function () { }); it("should set the appraiser address", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - expect(await manager.pricingStrategy()).to.eq(mockAppraiser.target); + const { manager, mockOracle } = await loadFixture(setupContracts); + expect(await manager.oracle()).to.eq(mockOracle.target); }); it("should set the token refs", async function () { - const { manager, mockUsdc, mockSpot, mockPool } = await loadFixture(setupContracts); + const { manager, mockPool } = await loadFixture(setupContracts); expect(await manager.POOL()).to.eq(mockPool.target); - expect(await manager.USDC()).to.eq(mockUsdc.target); - expect(await manager.SPOT()).to.eq(mockSpot.target); }); it("should return the decimals", async function () { const { manager } = await loadFixture(setupContracts); expect(await manager.decimals()).to.eq(18); }); + + it("should set initial parameters", async function () { + const { manager } = await loadFixture(setupContracts); + expect(await manager.prevWithinActiveZone()).to.eq(false); + const r = await manager.activeZoneDeviation(); + expect(r[0]).to.eq(percFP("0.95")); + expect(r[1]).to.eq(percFP("1.05")); + expect(await manager.concBandDeviationWidth()).to.eq(percFP("0.05")); + expect(await manager.fullRangeMaxUsdcBal()).to.eq(usdcFP("250000")); + }); }); - describe("#transferOwnership", function () { + describe("#updateOracle", function () { it("should fail to when called by non-owner", async function () { const { manager, addr1 } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); await expect( - manager.connect(addr1).transferOwnership(addr1.address), - ).to.be.revertedWith("Unauthorized caller"); + manager.connect(addr1).updateOracle(mockOracle.target), + ).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("should fail when decimals dont match", async function () { + const { manager } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [9]); + await expect(manager.updateOracle(mockOracle.target)).to.be.revertedWith( + "UnexpectedDecimals", + ); }); it("should succeed when called by owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await manager.transferOwnership(addr1.address); - expect(await manager.owner()).to.eq(await addr1.getAddress()); + const { manager } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); + await manager.updateOracle(mockOracle.target); + expect(await manager.oracle()).to.eq(mockOracle.target); }); }); - describe("#updatePricingStrategy", function () { + describe("#updateActiveZone", function () { it("should fail to when called by non-owner", async function () { const { manager, addr1 } = await loadFixture(setupContracts); await expect( - manager.connect(addr1).updatePricingStrategy(addr1.address), - ).to.be.revertedWith("Unauthorized caller"); + manager.connect(addr1).updateActiveZone([percFP("0.9"), percFP("1.1")]), + ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("should succeed when called by owner", async function () { + const { manager } = await loadFixture(setupContracts); + await manager.updateActiveZone([percFP("0.9"), percFP("1.1")]); + const r = await manager.activeZoneDeviation(); + expect(r[0]).to.eq(percFP("0.9")); + expect(r[1]).to.eq(percFP("1.1")); + }); + }); + + describe("#updateConcentratedBand", function () { + it("should fail to when called by non-owner", async function () { const { manager, addr1 } = await loadFixture(setupContracts); - await manager.updatePricingStrategy(addr1.address); - expect(await manager.pricingStrategy()).to.eq(await addr1.getAddress()); + await expect( + manager.connect(addr1).updateConcentratedBand(percFP("0.1")), + ).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("should succeed when called by owner", async function () { + const { manager } = await loadFixture(setupContracts); + await manager.updateConcentratedBand(percFP("0.1")); + expect(await manager.concBandDeviationWidth()).to.eq(percFP("0.1")); }); }); - describe("#setLiquidityRanges", function () { + describe("#updateFullRangeLiquidity", function () { it("should fail to when called by non-owner", async function () { const { manager, addr1 } = await loadFixture(setupContracts); await expect( - manager.connect(addr1).setLiquidityRanges(7200, 330000, 1200), - ).to.be.revertedWith("Unauthorized caller"); + manager.connect(addr1).updateFullRangeLiquidity(usdcFP("1000000"), percFP("0.2")), + ).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("should fail to when param is invalid", async function () { + const { manager } = await loadFixture(setupContracts); + await expect( + manager.updateFullRangeLiquidity(usdcFP("1000000"), percFP("1.2")), + ).to.be.revertedWith("InvalidPerc"); }); it("should succeed when called by owner", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockCall("setBaseThreshold(int24)", [7200], []); - await mockVault.mockCall("setFullRangeWeight(uint24)", [330000], []); - await mockVault.mockCall("setLimitThreshold(int24)", [1200], []); - await manager.setLiquidityRanges(7200, 330000, 1200); + const { manager } = await loadFixture(setupContracts); + await manager.updateFullRangeLiquidity(usdcFP("1000000"), percFP("0.2")); + expect(await manager.fullRangeMaxUsdcBal()).to.eq(usdcFP("1000000")); + expect(await manager.fullRangeMaxPerc()).to.eq(percFP("0.2")); }); }); @@ -143,7 +255,7 @@ describe("UsdcSpotManager", function () { .execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), ), - ).to.be.revertedWith("Unauthorized caller"); + ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("should succeed when called by owner", async function () { @@ -162,7 +274,7 @@ describe("UsdcSpotManager", function () { manager.execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), ), - ).to.be.revertedWith("Vault call failed"); + ).to.be.revertedWith("VaultExecutionFailed"); await mockVault.mockCall("acceptManager()", [], []); await manager.execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), @@ -170,274 +282,212 @@ describe("UsdcSpotManager", function () { }); }); - describe("#computeDeviationFactor", function () { - describe("when spot price is invalid", function () { - it("should return invalid", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - await mockAppraiser.mockMethod("perpPrice()", [priceFP("1.2"), false]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.0057863765655975")); - expect(r[1]).to.eq(false); + describe("isOverweightSpot", function () { + describe("when spot sell", function () { + it("should return true", async function () { + const { manager, mockVault } = await loadFixture(setupContracts); + await stubOverweightSpot(mockVault); + expect(await manager.isOverweightSpot()).to.eq(true); }); }); - describe("when usd price is invalid", function () { - it("should return invalid", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - await mockAppraiser.mockMethod("usdPrice()", [priceFP("0.8"), false]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.0057863765655975")); - expect(r[1]).to.eq(false); + describe("when spot buy", function () { + it("should return false", async function () { + const { manager, mockVault } = await loadFixture(setupContracts); + await stubOverweightUsdc(mockVault); + expect(await manager.isOverweightSpot()).to.eq(false); }); }); + }); - it("should return deviation factor", async function () { + describe("activeZone", function () { + it("should return state", async function () { const { manager } = await loadFixture(setupContracts); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.0057863765655975")); - expect(r[1]).to.eq(true); + expect(await manager.activeZone(percFP("0.949"))).to.eq(false); + expect(await manager.activeZone(percFP("0.95"))).to.eq(true); + expect(await manager.activeZone(percFP("0.975"))).to.eq(true); + expect(await manager.activeZone(percFP("1"))).to.eq(true); + expect(await manager.activeZone(percFP("1.025"))).to.eq(true); + expect(await manager.activeZone(percFP("1.05"))).to.eq(true); + expect(await manager.activeZone(percFP("1.051"))).to.eq(false); }); + }); - it("should return deviation factor", async function () { + describe("activeFullRangePerc", function () { + it("should calculate full range perc", async function () { const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [65800]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.1569216182711425")); - expect(r[1]).to.eq(true); + await manager.updateFullRangeLiquidity(usdcFP("25000"), percFP("0.2")); + await mockVault.mockMethod("getTotalAmounts()", [usdcFP("500000"), spotFP("0")]); + expect(await manager.activeFullRangePerc()).to.eq(percFP("0.05")); }); - - it("should return deviation factor", async function () { + it("should calculate full range perc", async function () { const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [67800]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("0.947216779268338333")); - expect(r[1]).to.eq(true); - }); - - it("should return deviation factor", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - await mockAppraiser.mockMethod("perpPrice()", [priceFP("1.5"), true]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("0.804629101252478")); - expect(r[1]).to.eq(true); + await manager.updateFullRangeLiquidity(usdcFP("250000"), percFP("0.1")); + await mockVault.mockMethod("getTotalAmounts()", [usdcFP("500000"), spotFP("10")]); + expect(await manager.activeFullRangePerc()).to.eq(percFP("0.1")); }); - - it("should return deviation factor", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - await mockAppraiser.mockMethod("perpPrice()", [priceFP("1"), true]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.206943651878717")); - expect(r[1]).to.eq(true); + it("should calculate full range perc", async function () { + const { manager, mockVault } = await loadFixture(setupContracts); + await manager.updateFullRangeLiquidity(usdcFP("250000"), percFP("1")); + await mockVault.mockMethod("getTotalAmounts()", [ + usdcFP("500000"), + spotFP("10000"), + ]); + expect(await manager.activeFullRangePerc()).to.eq(percFP("0.5")); }); + }); - it("should return deviation factor when perp price is invalid", async function () { - const { manager, mockAppraiser } = await loadFixture(setupContracts); - await mockAppraiser.mockMethod("perpPrice()", [priceFP("0"), true]); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("100")); - expect(r[1]).to.eq(true); + describe("deviationToTicks", function () { + it("should return ticks", async function () { + const { manager } = await loadFixture(setupContracts); + expect(await manager.deviationToTicks(percFP("0.1"))).to.eq(1000); + expect(await manager.deviationToTicks(percFP("0.05"))).to.eq(400); + expect(await manager.deviationToTicks(percFP("0.025"))).to.eq(200); + expect(await manager.deviationToTicks(percFP("0.01"))).to.eq(200); + expect(await manager.deviationToTicks(percFP("0"))).to.eq(200); }); }); - describe("isOverweightSpot", function () { - describe("when spot sell", function () { - it("should return true", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [30001]); - await mockVault.mockMethod("limitLower()", [20000]); - await mockVault.mockMethod("limitUpper()", [40000]); + describe("#rebalance", function () { + describe("when price is inside active range, previously outside", function () { + it("should force rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("0.98"), true]); + + await stubOverweightUsdc(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 200); + await stubForceRebalance(mockVault); + + expect(await manager.isOverweightSpot()).to.eq(false); + expect(await manager.prevWithinActiveZone()).to.eq(false); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(true); + }); + + it("should force rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("0.98"), true]); + + await stubOverweightSpot(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 600); + await stubForceRebalance(mockVault); + expect(await manager.isOverweightSpot()).to.eq(true); + expect(await manager.prevWithinActiveZone()).to.eq(false); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(true); }); }); - describe("when spot buy", function () { - it("should return false", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [29999]); - await mockVault.mockMethod("limitLower()", [20000]); - await mockVault.mockMethod("limitUpper()", [40000]); + describe("when price is outside active range, previously inside", function () { + it("should rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1"), true]); + await stubOverweightUsdc(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 400); + await stubForceRebalance(mockVault); + await manager.rebalance(); + + await mockVault.mockMethod("getTotalAmounts()", [ + usdcFP("1000000"), + spotFP("500000"), + ]); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("0.5"), true]); + await stubInactiveLiq(mockVault); + await stubTrimFullRangeLiq(mockVault, 75000); + await stubRemovedLimitRange(mockVault); + await stubForceRebalance(mockVault); + expect(await manager.isOverweightSpot()).to.eq(false); + expect(await manager.prevWithinActiveZone()).to.eq(true); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(false); }); }); - }); - describe("#rebalance", function () { - describe("when deviation is < 1 and goes > 1", function () { - describe("when overweight spot", function () { - it("should keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [66200]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightSpot()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833")); - }); - }); + describe("when price is inside active range, previously inside", function () { + it("should rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); - describe("when overweight usdc", function () { - it("should remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [66200]); - await mockVault.mockMethod("limitLower()", [73000]); - await mockVault.mockMethod("limitUpper()", [75000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 73000, 75000)], - [50000, 0, 0, 0, 0], - ); - - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [73000, 75000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightSpot()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833")); - }); - }); - }); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1"), true]); + await stubOverweightUsdc(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 400); + await stubForceRebalance(mockVault); + await manager.rebalance(); + + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1.02"), true]); + await stubActiveZoneLiq(mockVault, 500000, 400, 600); + await stubRebalance(mockVault); - describe("when deviation is > 1 and goes < 1", function () { - describe("when overweight spot", function () { - it("should remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [66200]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [67800]); - await mockVault.mockMethod("limitLower()", [60000]); - await mockVault.mockMethod("limitUpper()", [65000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 60000, 65000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [60000, 65000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833")); - expect(await manager.isOverweightSpot()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333")); - }); + expect(await manager.isOverweightSpot()).to.eq(false); + expect(await manager.prevWithinActiveZone()).to.eq(true); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(true); }); - describe("when overweight usdc", function () { - it("should keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [66200]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [67800]); - await mockVault.mockMethod("limitLower()", [75000]); - await mockVault.mockMethod("limitUpper()", [80000]); - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - - expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833")); - expect(await manager.isOverweightSpot()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333")); - }); + it("should rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1"), true]); + await stubOverweightUsdc(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 400); + await stubForceRebalance(mockVault); + await manager.rebalance(); + + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("1.02"), true]); + await stubOverweightSpot(mockVault); + await stubActiveZoneLiq(mockVault, 500000, 400, 200); + await stubRebalance(mockVault); + + expect(await manager.isOverweightSpot()).to.eq(true); + expect(await manager.prevWithinActiveZone()).to.eq(true); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(true); }); }); - describe("when deviation remains below 1", function () { - describe("when overweight spot", function () { - it("should not force rebalance", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [67800]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("rebalance()", []); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 40000, 45000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [40000, 45000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightSpot()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333")); - }); + describe("when price is outside active range, previously outside", function () { + it("should rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await mockVault.mockMethod("getTotalAmounts()", [ + usdcFP("2500000"), + spotFP("500000"), + ]); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("0.75"), true]); + await stubOverweightUsdc(mockVault); + await stubInactiveLiq(mockVault); + await stubTrimFullRangeLiq(mockVault, 90000); + await stubRemovedLimitRange(mockVault); + await stubRebalance(mockVault); + + expect(await manager.isOverweightSpot()).to.eq(false); + expect(await manager.prevWithinActiveZone()).to.eq(false); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(false); }); }); - describe("when deviation remains above 1", function () { - describe("when overweight usdc", function () { - it("should not force rebalance", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [66200]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await manager.rebalance(); - - await mockVault.clearMockCall("setPeriod(uint32)", [0]); - await mockVault.clearMockCall("setPeriod(uint32)", [86400]); - await mockVault.clearMockCall("period()", []); - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - - await mockVault.mockMethod("getTwap()", [66800]); - await mockVault.mockMethod("limitLower()", [75000]); - await mockVault.mockMethod("limitUpper()", [80000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 75000, 80000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - - expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833")); - expect(await manager.isOverweightSpot()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.0468312037404625")); - }); + describe("when price is invalid", function () { + it("should rebalance and update liquidity", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await mockVault.mockMethod("getTotalAmounts()", [ + usdcFP("2500000"), + spotFP("500000"), + ]); + await mockOracle.mockMethod("spotPriceDeviation()", [priceFP("0.75"), false]); + await stubOverweightUsdc(mockVault); + await stubInactiveLiq(mockVault); + await stubTrimFullRangeLiq(mockVault, 90000); + await stubRemovedLimitRange(mockVault); + await stubRebalance(mockVault); + + expect(await manager.isOverweightSpot()).to.eq(false); + expect(await manager.prevWithinActiveZone()).to.eq(false); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevWithinActiveZone()).to.eq(false); }); }); }); diff --git a/spot-vaults/test/WethWamplManager.ts b/spot-vaults/test/WethWamplManager.ts index 2506d5c6..71b1593a 100644 --- a/spot-vaults/test/WethWamplManager.ts +++ b/spot-vaults/test/WethWamplManager.ts @@ -4,12 +4,7 @@ import { expect } from "chai"; import { DMock, sciParseFloat, univ3PositionKey } from "./helpers"; export const percFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); -export const amplFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 9); -export const wamplFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); -export const ethOracleFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 8); -export const amplOracleFP = (a: string): BigInt => - ethers.parseUnits(sciParseFloat(a), 18); -const nowTS = () => parseInt(Date.now() / 1000); +export const priceFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); describe("WethWamplManager", function () { async function setupContracts() { @@ -20,12 +15,6 @@ describe("WethWamplManager", function () { // Deploy mock contracts const mockVault = new DMock("IAlphaProVault"); await mockVault.deploy(); - await mockVault.mockMethod("fullLower()", [-800000]); - await mockVault.mockMethod("fullUpper()", [800000]); - await mockVault.mockMethod("baseLower()", [45000]); - await mockVault.mockMethod("baseUpper()", [55000]); - await mockVault.mockMethod("getTwap()", [49875]); - await mockVault.mockMethod("limitThreshold()", [800000]); const mockPool = new DMock("IUniswapV3Pool"); await mockPool.deploy(); @@ -36,26 +25,26 @@ describe("WethWamplManager", function () { ); await mockPool.mockCall( "positions(bytes32)", - [univ3PositionKey(mockVault.target, 45000, 55000)], - [20000, 0, 0, 0, 0], + [univ3PositionKey(mockVault.target, -100000, 100000)], + [100000, 0, 0, 0, 0], ); + await mockPool.mockCall( + "positions(bytes32)", + [univ3PositionKey(mockVault.target, 20000, 40000)], + [50000, 0, 0, 0, 0], + ); + await mockVault.mockMethod("baseLower()", [-100000]); + await mockVault.mockMethod("baseUpper()", [100000]); + await mockVault.mockMethod("fullLower()", [-800000]); + await mockVault.mockMethod("fullUpper()", [800000]); + await mockVault.mockMethod("limitLower()", [20000]); + await mockVault.mockMethod("limitUpper()", [40000]); await mockVault.mockMethod("pool()", [mockPool.target]); - const mockCPIOracle = new DMock("IAmpleforthOracle"); - await mockCPIOracle.deploy(); - await mockCPIOracle.mockMethod("DECIMALS()", [18]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - - const mockETHOracle = new DMock("IChainlinkOracle"); - await mockETHOracle.deploy(); - await mockETHOracle.mockMethod("decimals()", [8]); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("1.2"), true]); const mockWeth = new DMock("IERC20Upgradeable"); await mockWeth.deploy(); @@ -63,27 +52,17 @@ describe("WethWamplManager", function () { const mockWampl = new DMock("IWAMPL"); await mockWampl.deploy(); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("18")], - ); await mockVault.mockMethod("token1()", [mockWampl.target]); // Deploy Manager contract const Manager = await ethers.getContractFactory("WethWamplManager"); - const manager = await Manager.deploy( - mockVault.target, - mockCPIOracle.target, - mockETHOracle.target, - ); + const manager = await Manager.deploy(mockVault.target, mockOracle.target); return { owner, addr1, mockVault, - mockCPIOracle, - mockETHOracle, + mockOracle, mockWeth, mockWampl, mockPool, @@ -91,6 +70,56 @@ describe("WethWamplManager", function () { }; } + async function stubRebalance(mockVault) { + await mockVault.clearMockMethod("setPeriod(uint32)"); + await mockVault.clearMockMethod("period()"); + await mockVault.mockMethod("rebalance()", []); + } + + async function stubForceRebalance(mockVault) { + await mockVault.mockMethod("period()", [86400]); + await mockVault.mockCall("setPeriod(uint32)", [0], []); + await mockVault.mockCall("setPeriod(uint32)", [86400], []); + await mockVault.mockMethod("rebalance()", []); + } + + async function stubOverweightWampl(mockVault) { + await mockVault.mockMethod("getTwap()", [30001]); + } + async function stubOverweightWeth(mockVault) { + await mockVault.mockMethod("getTwap()", [29999]); + await mockVault.mockMethod("limitLower()", [20000]); + await mockVault.mockMethod("limitUpper()", [40000]); + } + + async function stubTrimLiquidity(mockVault, burntLiq) { + await mockVault.mockCall( + "emergencyBurn(int24,int24,uint128)", + [-800000, 800000, burntLiq], + [], + ); + await mockVault.mockCall( + "emergencyBurn(int24,int24,uint128)", + [-100000, 100000, burntLiq], + [], + ); + } + + async function stubUnchangedLimitRange(mockVault) { + await mockVault.clearMockCall( + "emergencyBurn(int24,int24,uint128)", + [20000, 40000, 50000], + ); + } + + async function stubRemovedLimitRange(mockVault) { + await mockVault.mockCall( + "emergencyBurn(int24,int24,uint128)", + [20000, 40000, 50000], + [], + ); + } + describe("Initialization", function () { it("should set the correct owner", async function () { const { manager, owner } = await loadFixture(setupContracts); @@ -102,23 +131,14 @@ describe("WethWamplManager", function () { expect(await manager.VAULT()).to.eq(mockVault.target); }); - it("should set the correct CPI oracle address", async function () { - const { manager, mockCPIOracle } = await loadFixture(setupContracts); - expect(await manager.cpiOracle()).to.eq(mockCPIOracle.target); - }); - - it("should set the correct ETH oracle address", async function () { - const { manager, mockETHOracle } = await loadFixture(setupContracts); - expect(await manager.ethOracle()).to.eq(mockETHOracle.target); + it("should set the correct oracle address", async function () { + const { manager, mockOracle } = await loadFixture(setupContracts); + expect(await manager.oracle()).to.eq(mockOracle.target); }); it("should set the token refs", async function () { - const { manager, mockWeth, mockWampl, mockPool } = await loadFixture( - setupContracts, - ); + const { manager, mockPool } = await loadFixture(setupContracts); expect(await manager.POOL()).to.eq(mockPool.target); - expect(await manager.WETH()).to.eq(mockWeth.target); - expect(await manager.WAMPL()).to.eq(mockWampl.target); }); it("should set the active perc calculation params", async function () { @@ -145,48 +165,34 @@ describe("WethWamplManager", function () { }); }); - describe("#transferOwnership", function () { + describe("#updateOracle", function () { it("should fail to when called by non-owner", async function () { const { manager, addr1 } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); await expect( - manager.connect(addr1).transferOwnership(addr1.address), - ).to.be.revertedWith("Unauthorized caller"); - }); - - it("should succeed when called by owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await manager.transferOwnership(addr1.address); - expect(await manager.owner()).to.eq(await addr1.getAddress()); - }); - }); - - describe("#setCpiOracle", function () { - it("should fail to when called by non-owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await expect(manager.connect(addr1).setCpiOracle(addr1.address)).to.be.revertedWith( - "Unauthorized caller", - ); + manager.connect(addr1).updateOracle(mockOracle.target), + ).to.be.revertedWith("Ownable: caller is not the owner"); }); - it("should succeed when called by owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await manager.setCpiOracle(addr1.address); - expect(await manager.cpiOracle()).to.eq(await addr1.getAddress()); - }); - }); - - describe("#setEthOracle", function () { - it("should fail to when called by non-owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await expect(manager.connect(addr1).setEthOracle(addr1.address)).to.be.revertedWith( - "Unauthorized caller", + it("should fail when decimals dont match", async function () { + const { manager } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [9]); + await expect(manager.updateOracle(mockOracle.target)).to.be.revertedWith( + "UnexpectedDecimals", ); }); it("should succeed when called by owner", async function () { - const { manager, addr1 } = await loadFixture(setupContracts); - await manager.setEthOracle(addr1.address); - expect(await manager.ethOracle()).to.eq(await addr1.getAddress()); + const { manager } = await loadFixture(setupContracts); + const mockOracle = new DMock("IMetaOracle"); + await mockOracle.deploy(); + await mockOracle.mockMethod("decimals()", [18]); + await manager.updateOracle(mockOracle.target); + expect(await manager.oracle()).to.eq(mockOracle.target); }); }); @@ -201,7 +207,7 @@ describe("WethWamplManager", function () { [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], ), - ).to.be.revertedWith("Unauthorized caller"); + ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("should succeed when called by owner", async function () { @@ -233,7 +239,7 @@ describe("WethWamplManager", function () { const { manager, addr1 } = await loadFixture(setupContracts); await expect( manager.connect(addr1).setLiquidityRanges(7200, 330000, 1200), - ).to.be.revertedWith("Unauthorized caller"); + ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("should succeed when called by owner", async function () { @@ -254,7 +260,7 @@ describe("WethWamplManager", function () { .execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), ), - ).to.be.revertedWith("Unauthorized caller"); + ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("should succeed when called by owner", async function () { @@ -273,7 +279,7 @@ describe("WethWamplManager", function () { manager.execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), ), - ).to.be.revertedWith("Vault call failed"); + ).to.be.revertedWith("VaultExecutionFailed"); await mockVault.mockCall("acceptManager()", [], []); await manager.execOnVault( mockVault.refFactory.interface.encodeFunctionData("acceptManager"), @@ -298,145 +304,9 @@ describe("WethWamplManager", function () { expect(await manager.computeActiveLiqPerc(percFP("5"))).to.eq(percFP("0.2")); expect(await manager.computeActiveLiqPerc(percFP("10"))).to.eq(percFP("0.2")); expect(await manager.computeActiveLiqPerc(percFP("100000"))).to.eq(percFP("0.2")); - expect(await manager.computeActiveLiqPerc(ethers.MaxUint256)).to.eq(percFP("0.2")); - }); - }); - - describe("#computeDeviationFactor", function () { - describe("when cpi is invalid", function () { - it("should return invalid", async function () { - const { manager, mockETHOracle, mockCPIOracle, mockWampl } = await loadFixture( - setupContracts, - ); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), false]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("18")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.051378374404781289")); - expect(r[1]).to.eq(false); - }); - }); - - describe("when eth price is invalid", function () { - it("should return invalid", async function () { - const { manager, mockETHOracle, mockCPIOracle, mockWampl } = await loadFixture( - setupContracts, - ); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS() - 86400 * 7, - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("18")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.051378374404781289")); - expect(r[1]).to.eq(false); - }); - }); - - it("should return deviation factor", async function () { - const { manager, mockETHOracle, mockCPIOracle, mockWampl } = await loadFixture( - setupContracts, - ); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("18")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.051378374404781289")); - expect(r[1]).to.eq(true); - }); - - it("should return deviation factor", async function () { - const { manager, mockETHOracle, mockCPIOracle, mockWampl } = await loadFixture( - setupContracts, - ); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("10")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("1.892481073928606322")); - expect(r[1]).to.eq(true); - }); - - it("should return deviation factor", async function () { - const { manager, mockETHOracle, mockCPIOracle, mockWampl } = await loadFixture( - setupContracts, - ); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("25")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("0.756992429571442528")); - expect(r[1]).to.eq(true); - }); - - it("should return max deviation when price is too high", async function () { - const { manager, mockVault, mockETHOracle, mockCPIOracle, mockWampl } = - await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [1]); - await mockETHOracle.mockMethod("latestRoundData()", [ - 0, - ethOracleFP("3300"), - 0, - nowTS(), - 0, - ]); - await mockCPIOracle.mockMethod("getData()", [amplOracleFP("1.19"), true]); - await mockWampl.mockCall( - "wrapperToUnderlying(uint256)", - [wamplFP("1")], - [amplFP("18")], - ); - const r = await manager.computeDeviationFactor.staticCall(); - expect(r[0]).to.eq(percFP("100")); - expect(r[1]).to.eq(true); + expect( + await manager.computeActiveLiqPerc(percFP("1000000000000000000000000")), + ).to.eq(percFP("0.2")); }); }); @@ -444,9 +314,7 @@ describe("WethWamplManager", function () { describe("when wampl sell", function () { it("should return true", async function () { const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [30001]); - await mockVault.mockMethod("limitLower()", [20000]); - await mockVault.mockMethod("limitUpper()", [40000]); + await stubOverweightWampl(mockVault); expect(await manager.isOverweightWampl()).to.eq(true); }); }); @@ -454,427 +322,166 @@ describe("WethWamplManager", function () { describe("when wampl buy", function () { it("should return false", async function () { const { manager, mockVault } = await loadFixture(setupContracts); - await mockVault.mockMethod("getTwap()", [29999]); - await mockVault.mockMethod("limitLower()", [20000]); - await mockVault.mockMethod("limitUpper()", [40000]); + await stubOverweightWeth(mockVault); expect(await manager.isOverweightWampl()).to.eq(false); }); }); }); - describe("#rebalance", function () { - describe("when activePercDelta is within threshold", function () { - describe("when deviation is < 1 and goes > 1", function () { - describe("when overweight wampl", function () { - it("should trim liquidity & keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 7324], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 1464], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightWampl()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - }); - }); - - describe("when overweight weth", function () { - it("should trim liquidity & remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [50000]); - await mockVault.mockMethod("limitUpper()", [55000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 50000, 55000)], - [50000, 0, 0, 0, 0], - ); - - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 7324], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 1464], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [50000, 55000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightWampl()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - }); - }); + describe("shouldRemoveLimitRange", function () { + describe("is overweight wampl", function () { + it("should return bool", async function () { + const { manager, mockVault } = await loadFixture(setupContracts); + await stubOverweightWampl(mockVault); + expect(await manager.shouldRemoveLimitRange(percFP("1.01"))).to.eq(false); + expect(await manager.shouldRemoveLimitRange(percFP("1"))).to.eq(false); + expect(await manager.shouldRemoveLimitRange(percFP("0.99"))).to.eq(true); }); + }); - describe("when deviation is > 1 and goes < 1", function () { - describe("when overweight wampl", function () { - it("should trim liquidity & remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [52000]); - await mockVault.mockMethod("limitLower()", [50000]); - await mockVault.mockMethod("limitUpper()", [51000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 50000, 51000)], - [50000, 0, 0, 0, 0], - ); - - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 23982], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 4796], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [50000, 51000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - expect(await manager.isOverweightWampl()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.850111862770710708")); - }); - }); - - describe("when overweight weth", function () { - it("should trim liquidity & keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [52000]); - await mockVault.mockMethod("limitLower()", [53000]); - await mockVault.mockMethod("limitUpper()", [55000]); - - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 23982], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 4796], - [], - ); - - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - expect(await manager.isOverweightWampl()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.850111862770710708")); - }); - }); + describe("is overweight weth", function () { + it("should return bool", async function () { + const { manager, mockVault } = await loadFixture(setupContracts); + await stubOverweightWeth(mockVault); + expect(await manager.shouldRemoveLimitRange(percFP("1.01"))).to.eq(true); + expect(await manager.shouldRemoveLimitRange(percFP("1"))).to.eq(false); + expect(await manager.shouldRemoveLimitRange(percFP("0.99"))).to.eq(false); }); }); + }); - describe("when activePercDelta is outside threshold", function () { - describe("when deviation is < 1 and goes > 1", function () { - describe("when overweight wampl", function () { - it("should trim liquidity & keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 7324], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 1464], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightWampl()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - }); - }); - - describe("when overweight weth", function () { - it("should trim liquidity & remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [50000]); - await mockVault.mockMethod("limitUpper()", [55000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 50000, 55000)], - [50000, 0, 0, 0, 0], - ); - - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 7324], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 1464], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [50000, 55000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightWampl()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - }); - }); - }); + describe("shouldForceRebalance", function () { + it("should return bool", async function () { + const { manager } = await loadFixture(setupContracts); - describe("when deviation is > 1 and goes < 1", function () { - describe("when overweight wampl", function () { - it("should trim liquidity & remove limit range", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [52000]); - await mockVault.mockMethod("limitLower()", [50000]); - await mockVault.mockMethod("limitUpper()", [51000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 50000, 51000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 23982], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 4796], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [50000, 51000, 50000], - [], - ); - - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - expect(await manager.isOverweightWampl()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.850111862770710708")); - }); - }); - - describe("when overweight weth", function () { - it("should trim liquidity & keep limit range", async function () { - const { manager, mockVault } = await loadFixture(setupContracts); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - await manager.rebalance(); - - await mockVault.mockMethod("getTwap()", [52000]); - await mockVault.mockMethod("limitLower()", [53000]); - await mockVault.mockMethod("limitUpper()", [55000]); - - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [-800000, 800000, 23982], - [], - ); - await mockVault.mockCall( - "emergencyBurn(int24,int24,uint128)", - [45000, 55000, 4796], - [], - ); - - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - expect(await manager.isOverweightWampl()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.850111862770710708")); - }); - }); - }); + // inside active delta + expect( + await manager.shouldForceRebalance(percFP("0.5"), percFP("0.8"), percFP("0.09")), + ).to.eq(false); + expect( + await manager.shouldForceRebalance(percFP("0.9"), percFP("1.1"), percFP("0.09")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.0"), percFP("1.1"), percFP("0.09")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.05"), percFP("1.1"), percFP("0.09")), + ).to.eq(false); + expect( + await manager.shouldForceRebalance(percFP("1.1"), percFP("1"), percFP("0.09")), + ).to.eq(false); + expect( + await manager.shouldForceRebalance(percFP("1.1"), percFP("0.99"), percFP("0.09")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1"), percFP("0.8"), percFP("0.09")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("0.9"), percFP("0.8"), percFP("0.09")), + ).to.eq(false); + + // outside active delta + expect( + await manager.shouldForceRebalance(percFP("0.5"), percFP("0.8"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("0.9"), percFP("1.1"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.0"), percFP("1.1"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.05"), percFP("1.1"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.1"), percFP("1"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1.1"), percFP("0.99"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("1"), percFP("0.8"), percFP("1.1")), + ).to.eq(true); + expect( + await manager.shouldForceRebalance(percFP("0.9"), percFP("0.8"), percFP("1.1")), + ).to.eq(true); }); + }); - describe("when deviation remains below 1", function () { - describe("when overweight wampl", function () { - it("should not force rebalance", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [51500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 40000, 45000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - - expect(await manager.prevDeviation()).to.eq("0"); - expect(await manager.isOverweightWampl()).to.eq(true); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("0.893695795923885030")); - }); - }); + describe("#rebalance", function () { + it("should rebalance, trim liquidity and prev_deviation", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await stubOverweightWeth(mockVault); + await stubForceRebalance(mockVault); + await stubTrimLiquidity(mockVault, 1600); + await stubUnchangedLimitRange(mockVault); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("0.99"), true]); + + expect(await manager.isOverweightWampl()).to.eq(false); + expect(await manager.prevDeviation()).to.eq("0"); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevDeviation()).to.eq(percFP("0.99")); }); - describe("when deviation remains above 1", function () { - describe("when overweight weth", function () { - it("should not force rebalance", async function () { - const { manager, mockVault, mockPool } = await loadFixture(setupContracts); - await manager.setActivePercParams( - percFP("1"), - [percFP("0.5"), percFP("0.2"), percFP("1"), percFP("1")], - [percFP("1"), percFP("1"), percFP("2"), percFP("0.2")], - ); - - await mockVault.mockMethod("getTwap()", [49500]); - await mockVault.mockMethod("limitLower()", [40000]); - await mockVault.mockMethod("limitUpper()", [45000]); - await mockVault.mockMethod("period()", [86400]); - await mockVault.mockCall("setPeriod(uint32)", [0], []); - await mockVault.mockCall("setPeriod(uint32)", [86400], []); - await mockVault.mockMethod("rebalance()", []); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - await manager.rebalance(); - - await mockVault.clearMockCall("setPeriod(uint32)", [0]); - await mockVault.clearMockCall("setPeriod(uint32)", [86400]); - await mockVault.clearMockCall("period()", []); - await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)"); - - await mockVault.mockMethod("getTwap()", [50000]); - await mockVault.mockMethod("limitLower()", [53000]); - await mockVault.mockMethod("limitUpper()", [55000]); - await mockPool.mockCall( - "positions(bytes32)", - [univ3PositionKey(mockVault.target, 53000, 55000)], - [50000, 0, 0, 0, 0], - ); - await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []); - - expect(await manager.prevDeviation()).to.eq(percFP("1.091551595254704898")); - expect(await manager.isOverweightWampl()).to.eq(false); - await expect(manager.rebalance()).not.to.be.reverted; - expect(await manager.prevDeviation()).to.eq(percFP("1.038318591387163286")); - }); - }); + it("should rebalance, trim liquidity and prev_deviation", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await stubOverweightWampl(mockVault); + await stubForceRebalance(mockVault); + await stubTrimLiquidity(mockVault, 1600); + await stubRemovedLimitRange(mockVault); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("0.99"), true]); + + expect(await manager.isOverweightWampl()).to.eq(true); + expect(await manager.prevDeviation()).to.eq("0"); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevDeviation()).to.eq(percFP("0.99")); + }); + + it("should rebalance, trim liquidity and prev_deviation", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await stubOverweightWeth(mockVault); + await stubForceRebalance(mockVault); + await stubTrimLiquidity(mockVault, 16000); + await stubRemovedLimitRange(mockVault); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("1.2"), true]); + + expect(await manager.isOverweightWampl()).to.eq(false); + expect(await manager.prevDeviation()).to.eq("0"); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevDeviation()).to.eq(percFP("1.2")); + }); + + it("should rebalance, trim liquidity and prev_deviation", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await stubOverweightWampl(mockVault); + await stubForceRebalance(mockVault); + await stubTrimLiquidity(mockVault, 16000); + await stubUnchangedLimitRange(mockVault); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("1.2"), true]); + + expect(await manager.isOverweightWampl()).to.eq(true); + expect(await manager.prevDeviation()).to.eq("0"); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevDeviation()).to.eq(percFP("1.2")); + }); + + it("should rebalance, trim liquidity and not change prev_deviation", async function () { + const { manager, mockVault, mockOracle } = await loadFixture(setupContracts); + + await stubOverweightWampl(mockVault); + await stubRebalance(mockVault); + await stubTrimLiquidity(mockVault, 80000); + await stubRemovedLimitRange(mockVault); + await mockOracle.mockMethod("amplPriceDeviation()", [priceFP("1.2"), false]); + + expect(await manager.isOverweightWampl()).to.eq(true); + expect(await manager.prevDeviation()).to.eq("0"); + await expect(manager.rebalance()).not.to.be.reverted; + expect(await manager.prevDeviation()).to.eq(percFP("0")); }); }); }); diff --git a/spot-vaults/test/helpers.ts b/spot-vaults/test/helpers.ts index aa3bfa14..141635fd 100644 --- a/spot-vaults/test/helpers.ts +++ b/spot-vaults/test/helpers.ts @@ -3,13 +3,20 @@ import { Contract, ContractFactory } from "ethers"; export const sciParseFloat = (a: string): BigInt => a.includes("e") ? parseFloat(a).toFixed(18) : a; +export const percFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); +export const priceFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); + export const usdFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 6); export const perpFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 9); -export const percentageFP = (a: string): BigInt => - ethers.parseUnits(sciParseFloat(a), 18); -export const priceFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); export const lpAmtFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 24); -export const oracleAnsFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 8); +export const amplFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 9); +export const wamplFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); +export const wethFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); +export const usdOracleFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 8); +export const ethOracleFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 18); +export const amplOracleFP = (a: string): BigInt => + ethers.parseUnits(sciParseFloat(a), 18); +export const drFP = (a: string): BigInt => ethers.parseUnits(sciParseFloat(a), 8); export class DMock { private refArtifact: string; diff --git a/yarn.lock b/yarn.lock index 50ffa547..17ed29ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,20 +23,19 @@ __metadata: version: 0.0.0-use.local resolution: "@ampleforthorg/spot-contracts@workspace:spot-contracts" dependencies: - "@defi-wonderland/smock": ^2.3.4 "@ethersproject/abi": ^5.6.4 "@ethersproject/abstract-provider": ^5.7.0 "@ethersproject/abstract-signer": ^5.7.0 "@ethersproject/bytes": ^5.6.1 "@ethersproject/providers": ^5.6.8 - "@nomicfoundation/hardhat-chai-matchers": ^1.0.6 - "@nomicfoundation/hardhat-verify": ^1.1.0 - "@nomiclabs/hardhat-ethers": ^2.2.1 - "@nomiclabs/hardhat-waffle": ^2.0.3 - "@openzeppelin/contracts-upgradeable": ^4.7.3 - "@openzeppelin/hardhat-upgrades": ^1.19.0 + "@nomicfoundation/hardhat-chai-matchers": latest + "@nomicfoundation/hardhat-ethers": ^3.0.0 + "@nomicfoundation/hardhat-verify": latest + "@nomiclabs/hardhat-waffle": ^2.0.6 + "@openzeppelin/contracts-upgradeable": 4.7.3 + "@openzeppelin/hardhat-upgrades": ^3.0.4 "@openzeppelin/upgrades-core": latest - "@typechain/ethers-v5": ^10.1.0 + "@typechain/ethers-v6": ^0.5.1 "@typechain/hardhat": ^6.1.2 "@types/chai": ^4.3.1 "@types/mocha": ^9.1.1 @@ -56,11 +55,12 @@ __metadata: eslint-plugin-prettier: ^4.2.1 eslint-plugin-promise: ^6.0.0 eslint-plugin-unused-imports: ^3.0.0 - ethereum-waffle: ^3.4.4 - ethers: ^5.6.9 - ganache-cli: ^6.12.2 - hardhat: ^2.19.4 - hardhat-gas-reporter: ^1.0.9 + ethereum-waffle: latest + ethers: ^6.6.0 + ethers-v5: "npm:ethers@^5.7.0" + ganache-cli: latest + hardhat: ^2.23.0 + hardhat-gas-reporter: latest lodash: ^4.17.21 prettier: ^2.7.1 prettier-plugin-solidity: ^1.0.0-dev.23 @@ -157,7 +157,7 @@ __metadata: ethers: ^6.6.0 ethers-v5: "npm:ethers@^5.7.0" ganache-cli: latest - hardhat: ^2.22.8 + hardhat: ^2.22.18 hardhat-gas-reporter: latest lodash: ^4.17.21 prettier: ^2.7.1 @@ -257,47 +257,6 @@ __metadata: languageName: node linkType: hard -"@defi-wonderland/smock@npm:^2.3.4": - version: 2.4.0 - resolution: "@defi-wonderland/smock@npm:2.4.0" - dependencies: - "@nomicfoundation/ethereumjs-util": ^9.0.4 - diff: ^5.0.0 - lodash.isequal: ^4.5.0 - lodash.isequalwith: ^4.4.0 - rxjs: ^7.2.0 - semver: ^7.3.5 - peerDependencies: - "@ethersproject/abi": ^5 - "@ethersproject/abstract-provider": ^5 - "@ethersproject/abstract-signer": ^5 - "@nomiclabs/hardhat-ethers": ^2 - ethers: ^5 - hardhat: ^2.21.0 - checksum: 421f97cfa9a8f7bbdafc6521723f5ed0c3b7cd0462dc7d1a143a2de9cbdac46dd6acd7db619aa03a09d62695c5337fb17699259db2d5e4ddb530f5f55ef4ef30 - languageName: node - linkType: hard - -"@ensdomains/ens@npm:^0.4.4": - version: 0.4.5 - resolution: "@ensdomains/ens@npm:0.4.5" - dependencies: - bluebird: ^3.5.2 - eth-ens-namehash: ^2.0.8 - solc: ^0.4.20 - testrpc: 0.0.1 - web3-utils: ^1.0.0-beta.31 - checksum: 3b4f6e34f3376f1b3cc60927d53d5951c4da0a9ff0f8856aaedba5a73bceccb7c08632bf6709b3bb9e43d6e83223d23928f574fc62dec12b2b1a692bcd3d45c6 - languageName: node - linkType: hard - -"@ensdomains/resolver@npm:^0.2.4": - version: 0.2.4 - resolution: "@ensdomains/resolver@npm:0.2.4" - checksum: 3827a3430cc8935a0839dac9dafcfa6011c6f71af229ff91cbc6cdcbaa35d20c6dbb1a8a901cdb00e66428578ce1675bd6fe6901778b5d0d828321fbec9e0f7f - languageName: node - linkType: hard - "@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -353,16 +312,6 @@ __metadata: languageName: node linkType: hard -"@ethereum-waffle/chai@npm:^3.4.4": - version: 3.4.4 - resolution: "@ethereum-waffle/chai@npm:3.4.4" - dependencies: - "@ethereum-waffle/provider": ^3.4.4 - ethers: ^5.5.2 - checksum: b2b9b6b839c3f6b4abf8489fe50549e6fda07bd81ae8e4250b20d9a76ce4a729ef47c741364387b1d2dbc7fac14b46a5d6dcc4d404344b9cce5f9698ff012251 - languageName: node - linkType: hard - "@ethereum-waffle/compiler@npm:4.0.3": version: 4.0.3 resolution: "@ethereum-waffle/compiler@npm:4.0.3" @@ -382,25 +331,6 @@ __metadata: languageName: node linkType: hard -"@ethereum-waffle/compiler@npm:^3.4.4": - version: 3.4.4 - resolution: "@ethereum-waffle/compiler@npm:3.4.4" - dependencies: - "@resolver-engine/imports": ^0.3.3 - "@resolver-engine/imports-fs": ^0.3.3 - "@typechain/ethers-v5": ^2.0.0 - "@types/mkdirp": ^0.5.2 - "@types/node-fetch": ^2.5.5 - ethers: ^5.0.1 - mkdirp: ^0.5.1 - node-fetch: ^2.6.1 - solc: ^0.6.3 - ts-generator: ^0.1.1 - typechain: ^3.0.0 - checksum: ebffca732969253934c1e8cca6cc1f12d6294f848d44e6595af81460bc3230bc69096d0965b9deb2c7eecd472a1d536d8cbe993f95bfc76fbbe2114ddbabff70 - languageName: node - linkType: hard - "@ethereum-waffle/ens@npm:4.0.3": version: 4.0.3 resolution: "@ethereum-waffle/ens@npm:4.0.3" @@ -412,17 +342,6 @@ __metadata: languageName: node linkType: hard -"@ethereum-waffle/ens@npm:^3.4.4": - version: 3.4.4 - resolution: "@ethereum-waffle/ens@npm:3.4.4" - dependencies: - "@ensdomains/ens": ^0.4.4 - "@ensdomains/resolver": ^0.2.4 - ethers: ^5.5.2 - checksum: 71d93c09ef3ab89a46f05b9e2a06e129e2109d160c3a819e4bf3b4414fc4707e7fc646c87c1d82f9ba769dc1ac3c6f4934fd72499654fcfc9db4abf46c21d118 - languageName: node - linkType: hard - "@ethereum-waffle/mock-contract@npm:4.0.4": version: 4.0.4 resolution: "@ethereum-waffle/mock-contract@npm:4.0.4" @@ -432,16 +351,6 @@ __metadata: languageName: node linkType: hard -"@ethereum-waffle/mock-contract@npm:^3.4.4": - version: 3.4.4 - resolution: "@ethereum-waffle/mock-contract@npm:3.4.4" - dependencies: - "@ethersproject/abi": ^5.5.0 - ethers: ^5.5.2 - checksum: 6e5c62b342e424cd1937f2f7eb424056ad143b238320880f378c0db61c6d694617f968687321a2f030d546aa5b4dde42681cbb419589d7f87452c82844a4488b - languageName: node - linkType: hard - "@ethereum-waffle/provider@npm:4.0.5": version: 4.0.5 resolution: "@ethereum-waffle/provider@npm:4.0.5" @@ -456,19 +365,6 @@ __metadata: languageName: node linkType: hard -"@ethereum-waffle/provider@npm:^3.4.4": - version: 3.4.4 - resolution: "@ethereum-waffle/provider@npm:3.4.4" - dependencies: - "@ethereum-waffle/ens": ^3.4.4 - ethers: ^5.5.2 - ganache-core: ^2.13.2 - patch-package: ^6.2.2 - postinstall-postinstall: ^2.1.0 - checksum: 9e251d7b0198c22e337b18368e3893de766a821e818702dbef0e0d603bad550c6e3a29676cff11272bc82762833586ee9659593d957ec8759a8cc93c2b0f3d00 - languageName: node - linkType: hard - "@ethereumjs/block@npm:^3.5.0, @ethereumjs/block@npm:^3.6.0, @ethereumjs/block@npm:^3.6.2": version: 3.6.3 resolution: "@ethereumjs/block@npm:3.6.3" @@ -539,6 +435,15 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/rlp@npm:^5.0.2": + version: 5.0.2 + resolution: "@ethereumjs/rlp@npm:5.0.2" + bin: + rlp: bin/rlp.cjs + checksum: b569061ddb1f4cf56a82f7a677c735ba37f9e94e2bbaf567404beb9e2da7aa1f595e72fc12a17c61f7aec67fd5448443efe542967c685a2fe0ffc435793dcbab + languageName: node + linkType: hard + "@ethereumjs/tx@npm:3.4.0": version: 3.4.0 resolution: "@ethereumjs/tx@npm:3.4.0" @@ -570,6 +475,16 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/util@npm:^9.1.0": + version: 9.1.0 + resolution: "@ethereumjs/util@npm:9.1.0" + dependencies: + "@ethereumjs/rlp": ^5.0.2 + ethereum-cryptography: ^2.2.1 + checksum: 594e009c3001ca1ca658b4ded01b38e72f5dd5dd76389efd90cb020de099176a3327685557df268161ac3144333cfe8abaae68cda8ae035d9cc82409d386d79a + languageName: node + linkType: hard + "@ethereumjs/vm@npm:5.6.0": version: 5.6.0 resolution: "@ethereumjs/vm@npm:5.6.0" @@ -590,24 +505,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.0.0-beta.153": - version: 5.0.0-beta.153 - resolution: "@ethersproject/abi@npm:5.0.0-beta.153" - dependencies: - "@ethersproject/address": ">=5.0.0-beta.128" - "@ethersproject/bignumber": ">=5.0.0-beta.130" - "@ethersproject/bytes": ">=5.0.0-beta.129" - "@ethersproject/constants": ">=5.0.0-beta.128" - "@ethersproject/hash": ">=5.0.0-beta.128" - "@ethersproject/keccak256": ">=5.0.0-beta.127" - "@ethersproject/logger": ">=5.0.0-beta.129" - "@ethersproject/properties": ">=5.0.0-beta.131" - "@ethersproject/strings": ">=5.0.0-beta.130" - checksum: 9f5c3c986a47c2bcc066e0ea1d8190be4358de6722d0eb75eaaacbc1f7610169691cc369085aa390bd88c731c6e539f309cb81face594feffac9336e369444c5 - languageName: node - linkType: hard - -"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.9, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.6.3, @ethersproject/abi@npm:^5.6.4, @ethersproject/abi@npm:^5.7.0": +"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.9, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.6.4, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" dependencies: @@ -652,7 +550,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:5.7.0, @ethersproject/address@npm:>=5.0.0-beta.128, @ethersproject/address@npm:^5.0.2, @ethersproject/address@npm:^5.7.0": +"@ethersproject/address@npm:5.7.0, @ethersproject/address@npm:^5.0.2, @ethersproject/address@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/address@npm:5.7.0" dependencies: @@ -684,7 +582,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bignumber@npm:5.7.0, @ethersproject/bignumber@npm:>=5.0.0-beta.130, @ethersproject/bignumber@npm:^5.7.0": +"@ethersproject/bignumber@npm:5.7.0, @ethersproject/bignumber@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bignumber@npm:5.7.0" dependencies: @@ -695,7 +593,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:5.7.0, @ethersproject/bytes@npm:>=5.0.0-beta.129, @ethersproject/bytes@npm:^5.6.1, @ethersproject/bytes@npm:^5.7.0": +"@ethersproject/bytes@npm:5.7.0, @ethersproject/bytes@npm:^5.6.1, @ethersproject/bytes@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bytes@npm:5.7.0" dependencies: @@ -704,7 +602,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:5.7.0, @ethersproject/constants@npm:>=5.0.0-beta.128, @ethersproject/constants@npm:^5.7.0": +"@ethersproject/constants@npm:5.7.0, @ethersproject/constants@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/constants@npm:5.7.0" dependencies: @@ -731,7 +629,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hash@npm:5.7.0, @ethersproject/hash@npm:>=5.0.0-beta.128, @ethersproject/hash@npm:^5.7.0": +"@ethersproject/hash@npm:5.7.0, @ethersproject/hash@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/hash@npm:5.7.0" dependencies: @@ -789,7 +687,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/keccak256@npm:5.7.0, @ethersproject/keccak256@npm:>=5.0.0-beta.127, @ethersproject/keccak256@npm:^5.7.0": +"@ethersproject/keccak256@npm:5.7.0, @ethersproject/keccak256@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/keccak256@npm:5.7.0" dependencies: @@ -799,7 +697,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:5.7.0, @ethersproject/logger@npm:>=5.0.0-beta.129, @ethersproject/logger@npm:^5.7.0": +"@ethersproject/logger@npm:5.7.0, @ethersproject/logger@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/logger@npm:5.7.0" checksum: 075ab2f605f1fd0813f2e39c3308f77b44a67732b36e712d9bc085f22a84aac4da4f71b39bee50fe78da3e1c812673fadc41180c9970fe5e486e91ea17befe0d @@ -825,7 +723,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/properties@npm:5.7.0, @ethersproject/properties@npm:>=5.0.0-beta.131, @ethersproject/properties@npm:^5.7.0": +"@ethersproject/properties@npm:5.7.0, @ethersproject/properties@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/properties@npm:5.7.0" dependencies: @@ -921,7 +819,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:>=5.0.0-beta.130, @ethersproject/strings@npm:^5.7.0": +"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/strings@npm:5.7.0" dependencies: @@ -932,7 +830,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:5.7.0, @ethersproject/transactions@npm:^5.0.0-beta.135, @ethersproject/transactions@npm:^5.7.0": +"@ethersproject/transactions@npm:5.7.0, @ethersproject/transactions@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/transactions@npm:5.7.0" dependencies: @@ -1223,24 +1121,6 @@ __metadata: languageName: node linkType: hard -"@ljharb/resumer@npm:~0.0.1": - version: 0.0.1 - resolution: "@ljharb/resumer@npm:0.0.1" - dependencies: - "@ljharb/through": ^2.3.9 - checksum: 1cff0a485cb857933d2921cb05a349f8fe894fa2bb6b31a347010ecccc4a2b369e43ebe5383a32a60ee6c9572d2c83fcab383eb01727e1507bf29c59f312dae6 - languageName: node - linkType: hard - -"@ljharb/through@npm:^2.3.9, @ljharb/through@npm:~2.3.9": - version: 2.3.13 - resolution: "@ljharb/through@npm:2.3.13" - dependencies: - call-bind: ^1.0.7 - checksum: 0255464a0ec7901b08cff3e99370b87e66663f46249505959c0cb4f6121095d533bbb7c7cda338063d3e134cbdd721e2705bc18eac7611b4f9ead6e7935d13ba - languageName: node - linkType: hard - "@metamask/eth-sig-util@npm:^4.0.0": version: 4.0.1 resolution: "@metamask/eth-sig-util@npm:4.0.1" @@ -1272,6 +1152,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:~1.8.1": + version: 1.8.1 + resolution: "@noble/curves@npm:1.8.1" + dependencies: + "@noble/hashes": 1.7.1 + checksum: 4143f1248ed57c1ae46dfef5c692a91383e5830420b9c72d3ff1061aa9ebbf8999297da6d2aed8a9716fef8e6b1f5a45737feeab02abf55ca2a4f514bf9339ec + languageName: node + linkType: hard + "@noble/hashes@npm:1.2.0, @noble/hashes@npm:~1.2.0": version: 1.2.0 resolution: "@noble/hashes@npm:1.2.0" @@ -1293,6 +1182,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.7.1, @noble/hashes@npm:~1.7.1": + version: 1.7.1 + resolution: "@noble/hashes@npm:1.7.1" + checksum: 4f1b56428a10323feef17e4f437c9093556cb18db06f94d254043fadb69c3da8475f96eb3f8322d41e8670117d7486475a8875e68265c2839f60fd03edd6a616 + languageName: node + linkType: hard + "@noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2": version: 1.3.3 resolution: "@noble/hashes@npm:1.3.3" @@ -1334,131 +1230,131 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/edr-darwin-arm64@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.4.1" - checksum: 087e0e51a6181d85269097f1be667d7f07898b712d506c2c32218bde5f4e194a748165fa3fada3f827d2d47d1cf1b1374f34825468a41a3dd702f0476569b7f3 +"@nomicfoundation/edr-darwin-arm64@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.10.0" + checksum: 36fed73ecffa04931b7be27bf9b835044bf3d4ec4a65271c786416bd021e8bf44d457d5cfced5dbe1e64a83558ac861d048e2ac43807726802fc231be99d5c87 languageName: node linkType: hard -"@nomicfoundation/edr-darwin-arm64@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.5.2" - checksum: f6ab386603c6e080fe7f611b739eb6d1d6a370220318b725cb582702563577150b3be14b6d0be71cb72bdb854e6992c587ecfc6833216f750eae8e7cd96de46f +"@nomicfoundation/edr-darwin-arm64@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.7.0" + checksum: 15541029227f65df2cf1df93343f6c8e9484494ddf26cf12289cea7410446ce5b2ebb9ac750a7d438276c427da7678aba0fd8fda33ed7c1e8c743955fb657055 languageName: node linkType: hard -"@nomicfoundation/edr-darwin-x64@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-darwin-x64@npm:0.4.1" - checksum: bd02d7f19f762efe92c7abc7b56372c85689d810de0c97c74467f5431547d593b8ce69244675d96e682db8be4ff487c29c63b163e8878f5b541b21cb713fa9ab +"@nomicfoundation/edr-darwin-x64@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-darwin-x64@npm:0.10.0" + checksum: 3317f2c79e90198a1387e436ca403578c70281e829f88b8535d408766e7b47c96bdb705ce2d068786ac9a44a45e5bbd90d13c6206aea36ee43e0d1b49a10f3ae languageName: node linkType: hard -"@nomicfoundation/edr-darwin-x64@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-darwin-x64@npm:0.5.2" - checksum: 6f91f6d0294c0450e0501983f1de34a48582fe93f48428bc4b798ac93bb5483a96d626c2b4c62ac91102f00c826a3f9bfa16d748301440ebe1bbb2920ba3ba6d +"@nomicfoundation/edr-darwin-x64@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-darwin-x64@npm:0.7.0" + checksum: 4b7cbbe6e6b0484805814ca7f2151de780dfc6102d443126666a4e5a19955343cb6e709c0f99b3a80b0b07fce50d5c2cee9958c516a1c2b0f2ac568a30db1712 languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-gnu@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.4.1" - checksum: 9cdb065a35680e808717195321d412e500bbb0e8867579c9026194485774356e3203cfc757fc6e8b28371810a07184272f4e71001345f0cdc08cd577468a33e8 +"@nomicfoundation/edr-linux-arm64-gnu@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.10.0" + checksum: 4cbbf825b53600b1089bb8d3fe25e1cf55808484d1bbd003073012471fb4d38668bdab2226d879d66d8c3d554d361d51f3a3e6ee90b708dbe28c497f30da389c languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-gnu@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.5.2" - checksum: bd84cc2741bb2be3c3a60bae9dbb8ca7794a68b8675684c97f2c6e7310e5cba7efd1cf18d392d42481cda83fb478f83c0bd605104c5cf08bab44ec07669c3010 +"@nomicfoundation/edr-linux-arm64-gnu@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.7.0" + checksum: 836786bbe5f9ee9fce220c7177fd5f6565b4049e42ca8163d2676c01b211aa7c688d6662cf2e469ba44147bfeaf2152f5cc168aaba171af1507477511f3289cc languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-musl@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.4.1" - checksum: d4fb68393f93b0dca040ae3aff339ca83c94a4e12b54b3839b67ba699cc2ef4431cad6af38ae0c7c4c7a0fce0880cbf86d2092743e87e8dbb40074ec63431154 +"@nomicfoundation/edr-linux-arm64-musl@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.10.0" + checksum: 638cb8781fbec33bb63451859e41e32c9989efdd1ba68f90f68426cda11c069ac4ffe1962520ef7d61723be05566f671e84fd35594ce2c19199cfb37d89d425f languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-musl@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.5.2" - checksum: e7f7d82f16be1b26805bd90964c456aecb4a6a1397e87d507810d37bd383064271fa63932564e725fdb30868925334338ec459fe32f84fc11206644b7b37825c +"@nomicfoundation/edr-linux-arm64-musl@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.7.0" + checksum: 005faee82c11965430a72eaa8a55d87db0ea8b149b6d0f483b505e099152c7148a959412c387e143efc0fd51fb2221dae4e1d7004c83a9f323819db1049713f7 languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-gnu@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.4.1" - checksum: cff5ebd95f8bc86438d8d4294f8d41f6db92ca03d3b1f21dcac90617f51835901e83421ce5e3ff95d9e20e31e2f25733681a2fe92c560ab9f431fc138ff9c267 +"@nomicfoundation/edr-linux-x64-gnu@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.10.0" + checksum: 8f46fbbadd15c52b1582349e640206004506bbe7764161bf5d7cdd47f17b3ccb11929a9946d364bc13e699a2ef5419780ece61c52515a14d47993fc446ab698b languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-gnu@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.5.2" - checksum: ec025bf75227638b6b2cd01b7ba01b3ddaddf54c4d18d25e9d0364ac621981be2aaf124f4e60a88da5c9e267adb41a660a42668e2d6c9a6a57e55e8671fc76f1 +"@nomicfoundation/edr-linux-x64-gnu@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.7.0" + checksum: 18b60a0bbb7ad35240fc5f4bbe62cd83cdbc0c3e6a513d3bca3c291874d9cb02da7eb55ec3af0d8e273060347d588f80b7fbf304704c2c4cf9f7b302d4d1b466 languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-musl@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.4.1" - checksum: e4ee7c195b60f3d90fe710d1d5e15289e5fa56c0af485089d31f35fb3f8c98e3fb1494762c66790fa867c0b7dad26bdcbe1956697a9578015d31997ee564147a +"@nomicfoundation/edr-linux-x64-musl@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.10.0" + checksum: 9d79e15ec478f66028e84c74251e2e5c675bbee286e91aa2c6d6aefc91898de7fba8ba286eae0f4592dcb74ad69193fb9a99515e99314e5e0c6b10b0c539f651 languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-musl@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.5.2" - checksum: c9ff47f72645492383b2a598675878abc029b86325e2c457db1b2c4281916e11e4ef6336c355d40ae3c1736595bc43da51cfcf1e923464011f526f4db64c245b +"@nomicfoundation/edr-linux-x64-musl@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.7.0" + checksum: 84e4cc834f71db02e21ea218919e9cec67983894372c232d5f36519d2d5579268d0019eb4f548826bfd1677867c78a0db81fce26bced330b375da68c91458a38 languageName: node linkType: hard -"@nomicfoundation/edr-win32-x64-msvc@npm:0.4.1": - version: 0.4.1 - resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.4.1" - checksum: 0c2081ad3d2ce60f0ef8fd5aa876d070568fa038b371859d9d253c072c8db7d66674fa9ea1c722915a434e04a0a46463821bbea97e6bf577c50ec3def3819309 +"@nomicfoundation/edr-win32-x64-msvc@npm:0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.10.0" + checksum: 7a9214e6a8f4d9eb2df0d7c5a4fc3c32a8ac26d0a96dd2c921e31d6605dfbcd6bbdfed9cb636da027683a30accc985412e964026726d57572456434382d16557 languageName: node linkType: hard -"@nomicfoundation/edr-win32-x64-msvc@npm:0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.5.2" - checksum: 56da7a1283470dede413cda5f2fef96e10250ec7a25562254ca0cd8045a653212c91e40fbcf37330e7af4e036d3c3aed83ea617831f9c7a5424389c73c53ed4e +"@nomicfoundation/edr-win32-x64-msvc@npm:0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.7.0" + checksum: 9f070a202cecab2d1f28353e5d90cd113ef98b9473169c83b97ab140898bd47a301a0cae69733346fe4cc57c31aa6f3796ab3280f1316aa79d561fecd00cc222 languageName: node linkType: hard -"@nomicfoundation/edr@npm:^0.4.0": - version: 0.4.1 - resolution: "@nomicfoundation/edr@npm:0.4.1" +"@nomicfoundation/edr@npm:^0.10.0": + version: 0.10.0 + resolution: "@nomicfoundation/edr@npm:0.10.0" dependencies: - "@nomicfoundation/edr-darwin-arm64": 0.4.1 - "@nomicfoundation/edr-darwin-x64": 0.4.1 - "@nomicfoundation/edr-linux-arm64-gnu": 0.4.1 - "@nomicfoundation/edr-linux-arm64-musl": 0.4.1 - "@nomicfoundation/edr-linux-x64-gnu": 0.4.1 - "@nomicfoundation/edr-linux-x64-musl": 0.4.1 - "@nomicfoundation/edr-win32-x64-msvc": 0.4.1 - checksum: e3798101748df5d158a509e331c47754646071738721e10a30da95046066a61d4435de4e47e179279ce51ebb2f6e81bd0c9125f367c58bd46fca1abb0d0ee0dd + "@nomicfoundation/edr-darwin-arm64": 0.10.0 + "@nomicfoundation/edr-darwin-x64": 0.10.0 + "@nomicfoundation/edr-linux-arm64-gnu": 0.10.0 + "@nomicfoundation/edr-linux-arm64-musl": 0.10.0 + "@nomicfoundation/edr-linux-x64-gnu": 0.10.0 + "@nomicfoundation/edr-linux-x64-musl": 0.10.0 + "@nomicfoundation/edr-win32-x64-msvc": 0.10.0 + checksum: ede23be8cb2b6a070ff75eed168d00fc63410cd33b43579bd9148d88f1d22f7b6c8d5316e6fb23efda4b07ef933fd92197ba63f28528a975d2372e2ee8d15c1a languageName: node linkType: hard -"@nomicfoundation/edr@npm:^0.5.2": - version: 0.5.2 - resolution: "@nomicfoundation/edr@npm:0.5.2" +"@nomicfoundation/edr@npm:^0.7.0": + version: 0.7.0 + resolution: "@nomicfoundation/edr@npm:0.7.0" dependencies: - "@nomicfoundation/edr-darwin-arm64": 0.5.2 - "@nomicfoundation/edr-darwin-x64": 0.5.2 - "@nomicfoundation/edr-linux-arm64-gnu": 0.5.2 - "@nomicfoundation/edr-linux-arm64-musl": 0.5.2 - "@nomicfoundation/edr-linux-x64-gnu": 0.5.2 - "@nomicfoundation/edr-linux-x64-musl": 0.5.2 - "@nomicfoundation/edr-win32-x64-msvc": 0.5.2 - checksum: 336b1c7cad96fa78410f0c9cc9524abe9fb1e56384fe990b98bfd17f15f25b4665ad8f0525ccd9511f7c19173841fe712d50db993078629e2fc4047fda4665dc + "@nomicfoundation/edr-darwin-arm64": 0.7.0 + "@nomicfoundation/edr-darwin-x64": 0.7.0 + "@nomicfoundation/edr-linux-arm64-gnu": 0.7.0 + "@nomicfoundation/edr-linux-arm64-musl": 0.7.0 + "@nomicfoundation/edr-linux-x64-gnu": 0.7.0 + "@nomicfoundation/edr-linux-x64-musl": 0.7.0 + "@nomicfoundation/edr-win32-x64-msvc": 0.7.0 + checksum: 83c54e2e2815c57ce56262f1010a0c5a2917b366bcf0acfad7662cbf2ccf46fd281e66c6db67bca9db7d91f699254216708045e882fda08c81361f111a07cb48 languageName: node linkType: hard @@ -1497,7 +1393,7 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/ethereumjs-util@npm:9.0.4, @nomicfoundation/ethereumjs-util@npm:^9.0.4": +"@nomicfoundation/ethereumjs-util@npm:9.0.4": version: 9.0.4 resolution: "@nomicfoundation/ethereumjs-util@npm:9.0.4" dependencies: @@ -1512,24 +1408,6 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-chai-matchers@npm:^1.0.6": - version: 1.0.6 - resolution: "@nomicfoundation/hardhat-chai-matchers@npm:1.0.6" - dependencies: - "@ethersproject/abi": ^5.1.2 - "@types/chai-as-promised": ^7.1.3 - chai-as-promised: ^7.1.1 - deep-eql: ^4.0.1 - ordinal: ^1.0.3 - peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 - chai: ^4.2.0 - ethers: ^5.0.0 - hardhat: ^2.9.4 - checksum: c388e5ed9068f2ba7c227737ab7312dd03405d5fab195247b061f2fa52e700fbd0fb65359c2d4f2086f2905bfca642c19a9122d034533edd936f89aea65ac7f2 - languageName: node - linkType: hard - "@nomicfoundation/hardhat-chai-matchers@npm:latest": version: 2.0.7 resolution: "@nomicfoundation/hardhat-chai-matchers@npm:2.0.7" @@ -1610,25 +1488,6 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-verify@npm:^1.1.0": - version: 1.1.1 - resolution: "@nomicfoundation/hardhat-verify@npm:1.1.1" - dependencies: - "@ethersproject/abi": ^5.1.2 - "@ethersproject/address": ^5.0.2 - cbor: ^8.1.0 - chalk: ^2.4.2 - debug: ^4.1.1 - lodash.clonedeep: ^4.5.0 - semver: ^6.3.0 - table: ^6.8.0 - undici: ^5.14.0 - peerDependencies: - hardhat: ^2.0.4 - checksum: 2d83d32d6833f23fb62c30c68c9a2ab3956098030edcf459e69639960f059c72572d203bcf92f191c69c9cb0fbbf011a1113bacde1e3cbb28d5e812334f04f32 - languageName: node - linkType: hard - "@nomicfoundation/hardhat-verify@npm:latest": version: 2.0.8 resolution: "@nomicfoundation/hardhat-verify@npm:2.0.8" @@ -1727,17 +1586,7 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-ethers@npm:^2.2.1": - version: 2.2.3 - resolution: "@nomiclabs/hardhat-ethers@npm:2.2.3" - peerDependencies: - ethers: ^5.0.0 - hardhat: ^2.0.0 - checksum: 72321317e55eb510306e04c42353c5f7ceb42d086fc76cc740120da6e1635b7ad5bbf23a8d6b02bd590754adcf646618933111624085ab249b1ff3482e773226 - languageName: node - linkType: hard - -"@nomiclabs/hardhat-waffle@npm:^2.0.3, @nomiclabs/hardhat-waffle@npm:^2.0.6": +"@nomiclabs/hardhat-waffle@npm:^2.0.6": version: 2.0.6 resolution: "@nomiclabs/hardhat-waffle@npm:2.0.6" peerDependencies: @@ -1772,6 +1621,13 @@ __metadata: languageName: node linkType: hard +"@openzeppelin/contracts-upgradeable@npm:4.7.3": + version: 4.7.3 + resolution: "@openzeppelin/contracts-upgradeable@npm:4.7.3" + checksum: c9ffb40cb847a975d440204fc6a811f43af960050242f707332b984d29bd16dc242ffa0935de61867aeb9e0357fadedb16b09b276deda5e9775582face831021 + languageName: node + linkType: hard + "@openzeppelin/contracts-upgradeable@npm:4.9.6, @openzeppelin/contracts-upgradeable@npm:^4.1.0, @openzeppelin/contracts-upgradeable@npm:^4.7.3": version: 4.9.6 resolution: "@openzeppelin/contracts-upgradeable@npm:4.9.6" @@ -1793,19 +1649,6 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/defender-base-client@npm:^1.46.0": - version: 1.54.6 - resolution: "@openzeppelin/defender-base-client@npm:1.54.6" - dependencies: - amazon-cognito-identity-js: ^6.0.1 - async-retry: ^1.3.3 - axios: ^1.4.0 - lodash: ^4.17.19 - node-fetch: ^2.6.0 - checksum: 75b260a545fd734b7678d5591b29847f5211466bad25caca95fc24490c36d49b419b1ef06e6abc9dc6c9b4be97ae2957e033f3050a8675ddd246da817eaedd83 - languageName: node - linkType: hard - "@openzeppelin/defender-sdk-base-client@npm:^1.10.0, @openzeppelin/defender-sdk-base-client@npm:^1.13.4": version: 1.13.4 resolution: "@openzeppelin/defender-sdk-base-client@npm:1.13.4" @@ -1838,30 +1681,6 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/hardhat-upgrades@npm:^1.19.0": - version: 1.28.0 - resolution: "@openzeppelin/hardhat-upgrades@npm:1.28.0" - dependencies: - "@openzeppelin/defender-base-client": ^1.46.0 - "@openzeppelin/platform-deploy-client": ^0.8.0 - "@openzeppelin/upgrades-core": ^1.27.0 - chalk: ^4.1.0 - debug: ^4.1.1 - proper-lockfile: ^4.1.1 - peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 - ethers: ^5.0.5 - hardhat: ^2.0.2 - peerDependenciesMeta: - "@nomiclabs/harhdat-etherscan": - optional: true - bin: - migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js - checksum: b37a5eb7c3a5c1fb4ae6754f5fe1d6e93eb6bc143861f57babf5c7d66706ee3e44ca7d57db17ce2ec6c7014f09c269d506f62b3b116897407fdb0d1ff68f4925 - languageName: node - linkType: hard - "@openzeppelin/hardhat-upgrades@npm:^3.0.4": version: 3.2.0 resolution: "@openzeppelin/hardhat-upgrades@npm:3.2.0" @@ -1889,20 +1708,7 @@ __metadata: languageName: node linkType: hard -"@openzeppelin/platform-deploy-client@npm:^0.8.0": - version: 0.8.0 - resolution: "@openzeppelin/platform-deploy-client@npm:0.8.0" - dependencies: - "@ethersproject/abi": ^5.6.3 - "@openzeppelin/defender-base-client": ^1.46.0 - axios: ^0.21.2 - lodash: ^4.17.19 - node-fetch: ^2.6.0 - checksum: 0ce050e185a812c366ceef7dcfce526815babab9396275d9724f324a548ddfdca92ea9913ce61356dcd8c014fc495890c8e21afab4a197e0e14e761c698cce68 - languageName: node - linkType: hard - -"@openzeppelin/upgrades-core@npm:^1.27.0, @openzeppelin/upgrades-core@npm:^1.32.0, @openzeppelin/upgrades-core@npm:latest": +"@openzeppelin/upgrades-core@npm:^1.32.0, @openzeppelin/upgrades-core@npm:latest": version: 1.34.1 resolution: "@openzeppelin/upgrades-core@npm:1.34.1" dependencies: @@ -2059,6 +1865,13 @@ __metadata: languageName: node linkType: hard +"@scure/base@npm:~1.2.2": + version: 1.2.4 + resolution: "@scure/base@npm:1.2.4" + checksum: db554eb550a1bd17684af9282e1ad751050a13d4add0e83ad61cc496680d7d1c1c1120ca780e72935a293bb59721c20a006a53a5eec6f6b5bdcd702cf27c8cae + languageName: node + linkType: hard + "@scure/bip32@npm:1.1.5": version: 1.1.5 resolution: "@scure/bip32@npm:1.1.5" @@ -2204,20 +2017,6 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^0.14.0": - version: 0.14.0 - resolution: "@sindresorhus/is@npm:0.14.0" - checksum: 971e0441dd44ba3909b467219a5e242da0fc584048db5324cfb8048148fa8dcc9d44d71e3948972c4f6121d24e5da402ef191420d1266a95f713bb6d6e59c98a - languageName: node - linkType: hard - -"@sindresorhus/is@npm:^4.0.0": - version: 4.6.0 - resolution: "@sindresorhus/is@npm:4.6.0" - checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 - languageName: node - linkType: hard - "@smithy/types@npm:^3.1.0": version: 3.3.0 resolution: "@smithy/types@npm:3.3.0" @@ -2227,15 +2026,6 @@ __metadata: languageName: node linkType: hard -"@solidity-parser/parser@npm:^0.14.0": - version: 0.14.5 - resolution: "@solidity-parser/parser@npm:0.14.5" - dependencies: - antlr4ts: ^0.5.0-alpha.4 - checksum: 9e85a0d4f8a05a11db6022444b70b2f353e2358467b1cce44cdda703ae1e3c7337e1b8cbc2eec8e14a8f34f9c60b42f325e5fe9b3c934cc980e35091e292d7ee - languageName: node - linkType: hard - "@solidity-parser/parser@npm:^0.16.0": version: 0.16.2 resolution: "@solidity-parser/parser@npm:0.16.2" @@ -2259,24 +2049,6 @@ __metadata: languageName: node linkType: hard -"@szmarczak/http-timer@npm:^1.1.2": - version: 1.1.2 - resolution: "@szmarczak/http-timer@npm:1.1.2" - dependencies: - defer-to-connect: ^1.0.1 - checksum: 4d9158061c5f397c57b4988cde33a163244e4f02df16364f103971957a32886beb104d6180902cbe8b38cb940e234d9f98a4e486200deca621923f62f50a06fe - languageName: node - linkType: hard - -"@szmarczak/http-timer@npm:^4.0.5": - version: 4.0.6 - resolution: "@szmarczak/http-timer@npm:4.0.6" - dependencies: - defer-to-connect: ^2.0.0 - checksum: c29df3bcec6fc3bdec2b17981d89d9c9fc9bd7d0c9bcfe92821dc533f4440bc890ccde79971838b4ceed1921d456973c4180d7175ee1d0023ad0562240a58d95 - languageName: node - linkType: hard - "@trufflesuite/bigint-buffer@npm:1.1.10": version: 1.1.10 resolution: "@trufflesuite/bigint-buffer@npm:1.1.10" @@ -2325,7 +2097,7 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^10.0.0, @typechain/ethers-v5@npm:^10.1.0": +"@typechain/ethers-v5@npm:^10.0.0": version: 10.2.1 resolution: "@typechain/ethers-v5@npm:10.2.1" dependencies: @@ -2341,18 +2113,6 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^2.0.0": - version: 2.0.0 - resolution: "@typechain/ethers-v5@npm:2.0.0" - dependencies: - ethers: ^5.0.2 - peerDependencies: - ethers: ^5.0.0 - typechain: ^3.0.0 - checksum: 785430547f11de358c4018338f6f72aac113ece70d743aad410fff4eacbc3b4876d2e0d3389e1a56123afcf156f5c044ee72275342e45218448c23fe93d23915 - languageName: node - linkType: hard - "@typechain/ethers-v6@npm:^0.5.1": version: 0.5.1 resolution: "@typechain/ethers-v6@npm:0.5.1" @@ -2390,7 +2150,7 @@ __metadata: languageName: node linkType: hard -"@types/bn.js@npm:^4.11.3, @types/bn.js@npm:^4.11.5": +"@types/bn.js@npm:^4.11.3": version: 4.11.6 resolution: "@types/bn.js@npm:4.11.6" dependencies: @@ -2408,18 +2168,6 @@ __metadata: languageName: node linkType: hard -"@types/cacheable-request@npm:^6.0.1": - version: 6.0.3 - resolution: "@types/cacheable-request@npm:6.0.3" - dependencies: - "@types/http-cache-semantics": "*" - "@types/keyv": ^3.1.4 - "@types/node": "*" - "@types/responselike": ^1.0.0 - checksum: d9b26403fe65ce6b0cb3720b7030104c352bcb37e4fac2a7089a25a97de59c355fa08940658751f2f347a8512aa9d18fdb66ab3ade835975b2f454f2d5befbd9 - languageName: node - linkType: hard - "@types/chai-as-promised@npm:^7.1.3": version: 7.1.8 resolution: "@types/chai-as-promised@npm:7.1.8" @@ -2436,15 +2184,6 @@ __metadata: languageName: node linkType: hard -"@types/concat-stream@npm:^1.6.0": - version: 1.6.1 - resolution: "@types/concat-stream@npm:1.6.1" - dependencies: - "@types/node": "*" - checksum: 7d211e74331affd3578b5469244f5cef84a93775f38332adb3ef12413559a23862bc682c6873d0a404b01c9d5d5f7d3ae091fe835b435b633eb420e3055b3e56 - languageName: node - linkType: hard - "@types/connect@npm:^3.4.33": version: 3.4.38 resolution: "@types/connect@npm:3.4.38" @@ -2461,15 +2200,6 @@ __metadata: languageName: node linkType: hard -"@types/form-data@npm:0.0.33": - version: 0.0.33 - resolution: "@types/form-data@npm:0.0.33" - dependencies: - "@types/node": "*" - checksum: f0c283fdef2dd7191168a37b9cb2625af3cfbd7f72b5a514f938bea0a135669f79d736186d434b9e81150b47ef1bf20d97b188014a00583556fad6ce59fb9bbf - languageName: node - linkType: hard - "@types/glob@npm:^7.1.1": version: 7.2.0 resolution: "@types/glob@npm:7.2.0" @@ -2480,13 +2210,6 @@ __metadata: languageName: node linkType: hard -"@types/http-cache-semantics@npm:*": - version: 4.0.4 - resolution: "@types/http-cache-semantics@npm:4.0.4" - checksum: 7f4dd832e618bc1e271be49717d7b4066d77c2d4eed5b81198eb987e532bb3e1c7e02f45d77918185bad936f884b700c10cebe06305f50400f382ab75055f9e8 - languageName: node - linkType: hard - "@types/json-schema@npm:^7.0.3, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" @@ -2501,15 +2224,6 @@ __metadata: languageName: node linkType: hard -"@types/keyv@npm:^3.1.1, @types/keyv@npm:^3.1.4": - version: 3.1.4 - resolution: "@types/keyv@npm:3.1.4" - dependencies: - "@types/node": "*" - checksum: e009a2bfb50e90ca9b7c6e8f648f8464067271fd99116f881073fa6fa76dc8d0133181dd65e6614d5fb1220d671d67b0124aef7d97dc02d7e342ab143a47779d - languageName: node - linkType: hard - "@types/level-errors@npm:*": version: 3.0.2 resolution: "@types/level-errors@npm:3.0.2" @@ -2572,7 +2286,7 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.5, @types/node-fetch@npm:^2.6.1": +"@types/node-fetch@npm:^2.6.1": version: 2.6.11 resolution: "@types/node-fetch@npm:2.6.11" dependencies: @@ -2605,14 +2319,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^10.0.3": - version: 10.17.60 - resolution: "@types/node@npm:10.17.60" - checksum: 2cdb3a77d071ba8513e5e8306fa64bf50e3c3302390feeaeff1fd325dd25c8441369715dfc8e3701011a72fed5958c7dfa94eb9239a81b3c286caa4d97db6eef - languageName: node - linkType: hard - -"@types/node@npm:^12.12.54, @types/node@npm:^12.12.6": +"@types/node@npm:^12.12.54": version: 12.20.55 resolution: "@types/node@npm:12.20.55" checksum: e4f86785f4092706e0d3b0edff8dca5a13b45627e4b36700acd8dfe6ad53db71928c8dee914d4276c7fd3b6ccd829aa919811c9eb708a2c8e4c6eb3701178c37 @@ -2628,13 +2335,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^8.0.0": - version: 8.10.66 - resolution: "@types/node@npm:8.10.66" - checksum: c52039de862654a139abdc6a51de532a69dd80516ac35a959c3b3a2831ecbaaf065b0df5f9db943f5e28b544ebb9a891730d52b52f7a169b86a82bc060210000 - languageName: node - linkType: hard - "@types/parse-json@npm:^4.0.0": version: 4.0.2 resolution: "@types/parse-json@npm:4.0.2" @@ -2658,31 +2358,6 @@ __metadata: languageName: node linkType: hard -"@types/qs@npm:^6.2.31": - version: 6.9.15 - resolution: "@types/qs@npm:6.9.15" - checksum: 97d8208c2b82013b618e7a9fc14df6bd40a73e1385ac479b6896bafc7949a46201c15f42afd06e86a05e914f146f495f606b6fb65610cc60cf2e0ff743ec38a2 - languageName: node - linkType: hard - -"@types/resolve@npm:^0.0.8": - version: 0.0.8 - resolution: "@types/resolve@npm:0.0.8" - dependencies: - "@types/node": "*" - checksum: f241bb773ab14b14500623ac3b57c52006ce32b20426b6d8bf2fe5fdc0344f42c77ac0f94ff57b443ae1d320a1a86c62b4e47239f0321699404402fbeb24bad6 - languageName: node - linkType: hard - -"@types/responselike@npm:^1.0.0": - version: 1.0.3 - resolution: "@types/responselike@npm:1.0.3" - dependencies: - "@types/node": "*" - checksum: 6ac4b35723429b11b117e813c7acc42c3af8b5554caaf1fc750404c1ae59f9b7376bc69b9e9e194a5a97357a597c2228b7173d317320f0360d617b6425212f58 - languageName: node - linkType: hard - "@types/secp256k1@npm:^4.0.1": version: 4.0.6 resolution: "@types/secp256k1@npm:4.0.6" @@ -2994,13 +2669,6 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/lockfile@npm:^1.1.0": - version: 1.1.0 - resolution: "@yarnpkg/lockfile@npm:1.1.0" - checksum: 05b881b4866a3546861fee756e6d3812776ea47fa6eb7098f983d6d0eefa02e12b66c3fff931574120f196286a7ad4879ce02743c8bb2be36c6a576c7852083a - languageName: node - linkType: hard - "JSONStream@npm:1.3.2": version: 1.3.2 resolution: "JSONStream@npm:1.3.2" @@ -3070,33 +2738,6 @@ __metadata: languageName: node linkType: hard -"abstract-leveldown@npm:3.0.0": - version: 3.0.0 - resolution: "abstract-leveldown@npm:3.0.0" - dependencies: - xtend: ~4.0.0 - checksum: 1d3e65fc2288fd17955df3b0887fdd3d4fa7fcd816062014f872ea12a1e86e886151cbdc36abd2f243a810b7999252eaa30adf636ffe1be3103493ab37277e49 - languageName: node - linkType: hard - -"abstract-leveldown@npm:^2.4.1, abstract-leveldown@npm:~2.7.1": - version: 2.7.2 - resolution: "abstract-leveldown@npm:2.7.2" - dependencies: - xtend: ~4.0.0 - checksum: 97c45a05d8b5d24edf3855c1f9a19f919c4a189e387929745289a53116c80638339a7d4e50ad76d0ad2900166adaeaf2e0350dcdcd453e783cd8f04fd9bea17a - languageName: node - linkType: hard - -"abstract-leveldown@npm:^5.0.0, abstract-leveldown@npm:~5.0.0": - version: 5.0.0 - resolution: "abstract-leveldown@npm:5.0.0" - dependencies: - xtend: ~4.0.0 - checksum: d55d03cc7fad011d5fea30d26504b1a76123ec8edd3623d21f80ce0561c610b7ed1e00eb037c14746ec2b7ad8638586024f11d4a1476beee2c470c8cf27e3586 - languageName: node - linkType: hard - "abstract-leveldown@npm:^6.2.1": version: 6.3.0 resolution: "abstract-leveldown@npm:6.3.0" @@ -3124,15 +2765,6 @@ __metadata: languageName: node linkType: hard -"abstract-leveldown@npm:~2.6.0": - version: 2.6.3 - resolution: "abstract-leveldown@npm:2.6.3" - dependencies: - xtend: ~4.0.0 - checksum: 87b18580467c303c34c305620e2c3227010f64187d6b1cd60c2d1b9adc058b0c4de716e111e9493aaad0080cb7836601032c5084990cd713f86b6a78f1fab791 - languageName: node - linkType: hard - "abstract-leveldown@npm:~6.2.1": version: 6.2.3 resolution: "abstract-leveldown@npm:6.2.3" @@ -3146,16 +2778,6 @@ __metadata: languageName: node linkType: hard -"accepts@npm:~1.3.8": - version: 1.3.8 - resolution: "accepts@npm:1.3.8" - dependencies: - mime-types: ~2.1.34 - negotiator: 0.6.3 - checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 - languageName: node - linkType: hard - "acorn-jsx@npm:^5.2.0, acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -3213,13 +2835,6 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:^3.1.1": - version: 3.1.2 - resolution: "aes-js@npm:3.1.2" - checksum: 062154d50b1e433cc8c3b8ca7879f3a6375d5e79c2a507b2b6c4ec920b4cd851bf2afa7f65c98761a9da89c0ab618cbe6529e8e9a1c71f93290b53128fb8f712 - languageName: node - linkType: hard - "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -3272,7 +2887,7 @@ __metadata: languageName: node linkType: hard -"amazon-cognito-identity-js@npm:^6.0.1, amazon-cognito-identity-js@npm:^6.3.6": +"amazon-cognito-identity-js@npm:^6.3.6": version: 6.3.13 resolution: "amazon-cognito-identity-js@npm:6.3.13" dependencies: @@ -3340,13 +2955,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^2.0.0": - version: 2.1.1 - resolution: "ansi-regex@npm:2.1.1" - checksum: 190abd03e4ff86794f338a31795d262c1dfe8c91f7e01d04f13f646f1dcb16c5800818f886047876f1272f065570ab86b24b99089f8b68a0e11ff19aed4ca8f1 - languageName: node - linkType: hard - "ansi-regex@npm:^3.0.0": version: 3.0.1 resolution: "ansi-regex@npm:3.0.1" @@ -3375,13 +2983,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^2.2.1": - version: 2.2.1 - resolution: "ansi-styles@npm:2.2.1" - checksum: ebc0e00381f2a29000d1dac8466a640ce11943cef3bda3cd0020dc042e31e1058ab59bf6169cd794a54c3a7338a61ebc404b7c91e004092dd20e028c432c9c2c - languageName: node - linkType: hard - "ansi-styles@npm:^3.2.0, ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" @@ -3489,45 +3090,6 @@ __metadata: languageName: node linkType: hard -"arr-diff@npm:^4.0.0": - version: 4.0.0 - resolution: "arr-diff@npm:4.0.0" - checksum: ea7c8834842ad3869297f7915689bef3494fd5b102ac678c13ffccab672d3d1f35802b79e90c4cfec2f424af3392e44112d1ccf65da34562ed75e049597276a0 - languageName: node - linkType: hard - -"arr-flatten@npm:^1.1.0": - version: 1.1.0 - resolution: "arr-flatten@npm:1.1.0" - checksum: 963fe12564fca2f72c055f3f6c206b9e031f7c433a0c66ca9858b484821f248c5b1e5d53c8e4989d80d764cd776cf6d9b160ad05f47bdc63022bfd63b5455e22 - languageName: node - linkType: hard - -"arr-union@npm:^3.1.0": - version: 3.1.0 - resolution: "arr-union@npm:3.1.0" - checksum: b5b0408c6eb7591143c394f3be082fee690ddd21f0fdde0a0a01106799e847f67fcae1b7e56b0a0c173290e29c6aca9562e82b300708a268bc8f88f3d6613cb9 - languageName: node - linkType: hard - -"array-back@npm:^1.0.3, array-back@npm:^1.0.4": - version: 1.0.4 - resolution: "array-back@npm:1.0.4" - dependencies: - typical: ^2.6.0 - checksum: 37a8be4cd4920b3d07bdbef40dae83bb37948f5d49601da98a6e48ba5496e9a0008e7f3f2184bcf4d3501bd371a048c9bdca7dc3cc5c3d5b1eb189bbba7b55db - languageName: node - linkType: hard - -"array-back@npm:^2.0.0": - version: 2.0.0 - resolution: "array-back@npm:2.0.0" - dependencies: - typical: ^2.6.1 - checksum: ab36ab3504b25116b47541fb0ac78ff13d1e991f33d98c361edd3aada3ed818a900b619bd67b195dd4e41b9256c27e8cdd6a69ece507e482f1207d07670ed6bd - languageName: node - linkType: hard - "array-back@npm:^3.0.1, array-back@npm:^3.1.0": version: 3.1.0 resolution: "array-back@npm:3.1.0" @@ -3552,13 +3114,6 @@ __metadata: languageName: node linkType: hard -"array-flatten@npm:1.1.1": - version: 1.1.1 - resolution: "array-flatten@npm:1.1.1" - checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b - languageName: node - linkType: hard - "array-includes@npm:^3.1.7": version: 3.1.8 resolution: "array-includes@npm:3.1.8" @@ -3580,20 +3135,6 @@ __metadata: languageName: node linkType: hard -"array-uniq@npm:1.0.3": - version: 1.0.3 - resolution: "array-uniq@npm:1.0.3" - checksum: 1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e - languageName: node - linkType: hard - -"array-unique@npm:^0.3.2": - version: 0.3.2 - resolution: "array-unique@npm:0.3.2" - checksum: da344b89cfa6b0a5c221f965c21638bfb76b57b45184a01135382186924f55973cd9b171d4dad6bf606c6d9d36b0d721d091afdc9791535ead97ccbe78f8a888 - languageName: node - linkType: hard - "array.prototype.findlast@npm:^1.2.2": version: 1.2.5 resolution: "array.prototype.findlast@npm:1.2.5" @@ -3646,21 +3187,6 @@ __metadata: languageName: node linkType: hard -"array.prototype.reduce@npm:^1.0.6": - version: 1.0.7 - resolution: "array.prototype.reduce@npm:1.0.7" - dependencies: - call-bind: ^1.0.7 - define-properties: ^1.2.1 - es-abstract: ^1.23.2 - es-array-method-boxes-properly: ^1.0.0 - es-errors: ^1.3.0 - es-object-atoms: ^1.0.0 - is-string: ^1.0.7 - checksum: 90303617bd70c8e9a81ebff041d3e10fad1a97f163699cb015b7c84a3f9e6960d9bb161a30f1d0309d6e476f166af5668c1e24f7add3202213d25f7c7f15475d - languageName: node - linkType: hard - "arraybuffer.prototype.slice@npm:^1.0.3": version: 1.0.3 resolution: "arraybuffer.prototype.slice@npm:1.0.3" @@ -3677,24 +3203,6 @@ __metadata: languageName: node linkType: hard -"asap@npm:~2.0.6": - version: 2.0.6 - resolution: "asap@npm:2.0.6" - checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d - languageName: node - linkType: hard - -"asn1.js@npm:^4.10.1": - version: 4.10.1 - resolution: "asn1.js@npm:4.10.1" - dependencies: - bn.js: ^4.0.0 - inherits: ^2.0.1 - minimalistic-assert: ^1.0.0 - checksum: 9289a1a55401238755e3142511d7b8f6fc32f08c86ff68bd7100da8b6c186179dd6b14234fba2f7f6099afcd6758a816708485efe44bc5b2a6ec87d9ceeddbb5 - languageName: node - linkType: hard - "asn1@npm:~0.2.3": version: 0.2.6 resolution: "asn1@npm:0.2.6" @@ -3735,13 +3243,6 @@ __metadata: languageName: node linkType: hard -"assign-symbols@npm:^1.0.0": - version: 1.0.0 - resolution: "assign-symbols@npm:1.0.0" - checksum: c0eb895911d05b6b2d245154f70461c5e42c107457972e5ebba38d48967870dee53bcdf6c7047990586daa80fab8dab3cc6300800fbd47b454247fdedd859a2c - languageName: node - linkType: hard - "ast-parents@npm:^0.0.1": version: 0.0.1 resolution: "ast-parents@npm:0.0.1" @@ -3763,7 +3264,7 @@ __metadata: languageName: node linkType: hard -"async-eventemitter@npm:^0.2.2, async-eventemitter@npm:^0.2.4": +"async-eventemitter@npm:^0.2.4": version: 0.2.4 resolution: "async-eventemitter@npm:0.2.4" dependencies: @@ -3772,13 +3273,6 @@ __metadata: languageName: node linkType: hard -"async-limiter@npm:~1.0.0": - version: 1.0.1 - resolution: "async-limiter@npm:1.0.1" - checksum: 2b849695b465d93ad44c116220dee29a5aeb63adac16c1088983c339b0de57d76e82533e8e364a93a9f997f28bbfc6a92948cefc120652bd07f3b59f8d75cf2b - languageName: node - linkType: hard - "async-retry@npm:^1.3.3": version: 1.3.3 resolution: "async-retry@npm:1.3.3" @@ -3788,23 +3282,14 @@ __metadata: languageName: node linkType: hard -"async@npm:1.x, async@npm:^1.4.2": +"async@npm:1.x": version: 1.5.2 resolution: "async@npm:1.5.2" checksum: fe5d6214d8f15bd51eee5ae8ec5079b228b86d2d595f47b16369dec2e11b3ff75a567bb5f70d12d79006665fbbb7ee0a7ec0e388524eefd454ecbe651c124ebd languageName: node linkType: hard -"async@npm:2.6.2": - version: 2.6.2 - resolution: "async@npm:2.6.2" - dependencies: - lodash: ^4.17.11 - checksum: e5e90a3bcc4d9bf964bfc6b77d63b8f5bee8c14e9a51c3317dbcace44d5b6b1fe01cd4fd347449704a107da7fcd25e1382ee8545957b2702782ae720605cf7a4 - languageName: node - linkType: hard - -"async@npm:^2.0.1, async@npm:^2.1.2, async@npm:^2.4.0, async@npm:^2.5.0, async@npm:^2.6.1": +"async@npm:^2.4.0": version: 2.6.4 resolution: "async@npm:2.6.4" dependencies: @@ -3827,15 +3312,6 @@ __metadata: languageName: node linkType: hard -"atob@npm:^2.1.2": - version: 2.1.2 - resolution: "atob@npm:2.1.2" - bin: - atob: bin/atob.js - checksum: dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a - languageName: node - linkType: hard - "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -3859,7 +3335,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.21.2, axios@npm:^0.21.4": +"axios@npm:^0.21.4": version: 0.21.4 resolution: "axios@npm:0.21.4" dependencies: @@ -3868,7 +3344,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.4.0, axios@npm:^1.5.1, axios@npm:^1.6.7, axios@npm:^1.6.8": +"axios@npm:^1.6.7, axios@npm:^1.6.8": version: 1.7.2 resolution: "axios@npm:1.7.2" dependencies: @@ -3879,895 +3355,184 @@ __metadata: languageName: node linkType: hard -"babel-code-frame@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-code-frame@npm:6.26.0" - dependencies: - chalk: ^1.1.3 - esutils: ^2.0.2 - js-tokens: ^3.0.2 - checksum: 9410c3d5a921eb02fa409675d1a758e493323a49e7b9dddb7a2a24d47e61d39ab1129dd29f9175836eac9ce8b1d4c0a0718fcdc57ce0b865b529fd250dbab313 - languageName: node - linkType: hard - -"babel-core@npm:^6.0.14, babel-core@npm:^6.26.0": - version: 6.26.3 - resolution: "babel-core@npm:6.26.3" - dependencies: - babel-code-frame: ^6.26.0 - babel-generator: ^6.26.0 - babel-helpers: ^6.24.1 - babel-messages: ^6.23.0 - babel-register: ^6.26.0 - babel-runtime: ^6.26.0 - babel-template: ^6.26.0 - babel-traverse: ^6.26.0 - babel-types: ^6.26.0 - babylon: ^6.18.0 - convert-source-map: ^1.5.1 - debug: ^2.6.9 - json5: ^0.5.1 - lodash: ^4.17.4 - minimatch: ^3.0.4 - path-is-absolute: ^1.0.1 - private: ^0.1.8 - slash: ^1.0.0 - source-map: ^0.5.7 - checksum: 3d6a37e5c69ea7f7d66c2a261cbd7219197f2f938700e6ebbabb6d84a03f2bf86691ffa066866dcb49ba6c4bd702d347c9e0e147660847d709705cf43c964752 +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 languageName: node linkType: hard -"babel-generator@npm:^6.26.0": - version: 6.26.1 - resolution: "babel-generator@npm:6.26.1" +"base-x@npm:^3.0.2": + version: 3.0.9 + resolution: "base-x@npm:3.0.9" dependencies: - babel-messages: ^6.23.0 - babel-runtime: ^6.26.0 - babel-types: ^6.26.0 - detect-indent: ^4.0.0 - jsesc: ^1.3.0 - lodash: ^4.17.4 - source-map: ^0.5.7 - trim-right: ^1.0.1 - checksum: 5397f4d4d1243e7157e3336be96c10fcb1f29f73bf2d9842229c71764d9a6431397d249483a38c4d8b1581459e67be4df6f32d26b1666f02d0f5bfc2c2f25193 + safe-buffer: ^5.0.1 + checksum: 957101d6fd09e1903e846fd8f69fd7e5e3e50254383e61ab667c725866bec54e5ece5ba49ce385128ae48f9ec93a26567d1d5ebb91f4d56ef4a9cc0d5a5481e8 languageName: node linkType: hard -"babel-helper-builder-binary-assignment-operator-visitor@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-builder-binary-assignment-operator-visitor@npm:6.24.1" - dependencies: - babel-helper-explode-assignable-expression: ^6.24.1 - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 6ef49597837d042980e78284df014972daac7f1f1f2635d978bb2d13990304322f5135f27b8f2d6eb8c4c2459b496ec76e21544e26afbb5dec88f53089e17476 +"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 languageName: node linkType: hard -"babel-helper-call-delegate@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-call-delegate@npm:6.24.1" - dependencies: - babel-helper-hoist-variables: ^6.24.1 - babel-runtime: ^6.22.0 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: b6277d6e48c10cf416632f6dfbac77bdf6ba8ec4ac2f6359a77d6b731dae941c2a3ec7f35e1eba78aad2a7e0838197731d1ef75af529055096c4cb7d96432c88 +"base64-sol@npm:1.0.1": + version: 1.0.1 + resolution: "base64-sol@npm:1.0.1" + checksum: be0f9e8cf3c744256913223fbae8187773f530cc096e98a77f49ef0bd6cedeb294d15a784e439419f7cb99f07bf85b08999169feafafa1a9e29c3affc0bc6d0a languageName: node linkType: hard -"babel-helper-define-map@npm:^6.24.1": - version: 6.26.0 - resolution: "babel-helper-define-map@npm:6.26.0" +"bcrypt-pbkdf@npm:^1.0.0": + version: 1.0.2 + resolution: "bcrypt-pbkdf@npm:1.0.2" dependencies: - babel-helper-function-name: ^6.24.1 - babel-runtime: ^6.26.0 - babel-types: ^6.26.0 - lodash: ^4.17.4 - checksum: 08e201eb009a7dbd020232fb7468ac772ebb8cfd33ec9a41113a54f4c90fd1e3474497783d635b8f87d797706323ca0c1758c516a630b0c95277112fc2fe4f13 + tweetnacl: ^0.14.3 + checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291 languageName: node linkType: hard -"babel-helper-explode-assignable-expression@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-explode-assignable-expression@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: 1bafdb51ce3dd95cf25d712d24a0c3c2ae02ff58118c77462f14ede4d8161aaee42c5c759c3d3a3344a5851b8b0f8d16b395713413b8194e1c3264fc5b12b754 +"bech32@npm:1.1.4": + version: 1.1.4 + resolution: "bech32@npm:1.1.4" + checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b languageName: node linkType: hard -"babel-helper-function-name@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-function-name@npm:6.24.1" - dependencies: - babel-helper-get-function-arity: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: d651db9e0b29e135877e90e7858405750a684220d22a6f7c78bb163305a1b322cc1c8bea1bc617625c34d92d0927fdbaa49ee46822e2f86b524eced4c88c7ff0 +"bignumber.js@npm:^9.0.0": + version: 9.1.2 + resolution: "bignumber.js@npm:9.1.2" + checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf languageName: node linkType: hard -"babel-helper-get-function-arity@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-get-function-arity@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 37e344d6c5c00b67a3b378490a5d7ba924bab1c2ccd6ecf1b7da96ca679be12d75fbec6279366ae9772e482fb06a7b48293954dd79cbeba9b947e2db67252fbd +"binary-extensions@npm:^2.0.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: bcad01494e8a9283abf18c1b967af65ee79b0c6a9e6fcfafebfe91dbe6e0fc7272bafb73389e198b310516ae04f7ad17d79aacf6cb4c0d5d5202a7e2e52c7d98 languageName: node linkType: hard -"babel-helper-hoist-variables@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-hoist-variables@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 6af1c165d5f0ad192df07daa194d13de77572bd914d2fc9a270d56b93b2705d98eebabf412b1211505535af131fbe95886fcfad8b3a07b4d501c24b9cb8e57fe +"binaryen@npm:77.0.0-nightly.20190407": + version: 77.0.0-nightly.20190407 + resolution: "binaryen@npm:77.0.0-nightly.20190407" + bin: + binaryen-as: bin/as.js + binaryen-dis: bin/dis.js + binaryen-opt: bin/opt.js + checksum: 756334720191ec02b28b1fa153009338bee63ead43d5923faa7c651b7b97183b020f2ade712fab45d4cc714cae5bfeef3e8a5624246f87207ee4d847e181f6a9 languageName: node linkType: hard -"babel-helper-optimise-call-expression@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-optimise-call-expression@npm:6.24.1" +"bip39@npm:3.0.4": + version: 3.0.4 + resolution: "bip39@npm:3.0.4" dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 16e6aba819b473dbf013391f759497df9f57bc7060bc4e5f7f6b60fb03670eb1dec65dd2227601d58f151e9d647e1f676a12466f5e6674379978820fa02c0fbb + "@types/node": 11.11.6 + create-hash: ^1.1.0 + pbkdf2: ^3.0.9 + randombytes: ^2.0.1 + checksum: 79ce1600a03d1ba5053bdd4e6323f9463ec340764c7e52918b6c6b9dca81221940f2d9a65656447f108f9bc2c8d9ae8df319cca83bbd1dad63f53ef2768d9bae languageName: node linkType: hard -"babel-helper-regex@npm:^6.24.1": - version: 6.26.0 - resolution: "babel-helper-regex@npm:6.26.0" +"bl@npm:^1.0.0": + version: 1.2.3 + resolution: "bl@npm:1.2.3" dependencies: - babel-runtime: ^6.26.0 - babel-types: ^6.26.0 - lodash: ^4.17.4 - checksum: ab949a4c90ab255abaafd9ec11a4a6dc77dba360875af2bb0822b699c058858773792c1e969c425c396837f61009f30c9ee5ba4b9a8ca87b0779ae1622f89fb3 + readable-stream: ^2.3.5 + safe-buffer: ^5.1.1 + checksum: 123f097989ce2fa9087ce761cd41176aaaec864e28f7dfe5c7dab8ae16d66d9844f849c3ad688eb357e3c5e4f49b573e3c0780bb8bc937206735a3b6f8569a5f languageName: node linkType: hard -"babel-helper-remap-async-to-generator@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-remap-async-to-generator@npm:6.24.1" - dependencies: - babel-helper-function-name: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: f330943104b61e7f9248d222bd5fe5d3238904ee20643b76197571e14a724723d64a8096b292a60f64788f0efe30176882c376eeebde00657925678e304324f0 +"blakejs@npm:^1.1.0": + version: 1.2.1 + resolution: "blakejs@npm:1.2.1" + checksum: d699ba116cfa21d0b01d12014a03e484dd76d483133e6dc9eb415aa70a119f08beb3bcefb8c71840106a00b542cba77383f8be60cd1f0d4589cb8afb922eefbe languageName: node linkType: hard -"babel-helper-replace-supers@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helper-replace-supers@npm:6.24.1" +"blob-to-it@npm:^1.0.1": + version: 1.0.4 + resolution: "blob-to-it@npm:1.0.4" dependencies: - babel-helper-optimise-call-expression: ^6.24.1 - babel-messages: ^6.23.0 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: ca1d216c5c6afc6af2ef55ea16777ba99e108780ea25da61d93edb09fd85f5e96c756306e2a21e737c3b0c7a16c99762b62a0e5f529d3865b14029fef7351cba + browser-readablestream-to-it: ^1.0.3 + checksum: e7fbebe5bd7b8187a4a88203639777456596a0cc68372e7b2dbcfbae6dea2b80e2a89522140039b538140bc3e3a6b1e90d1778e725eb8899070f799e61591751 languageName: node linkType: hard -"babel-helpers@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helpers@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - checksum: 751c6010e18648eebae422adfea5f3b5eff70d592d693bfe0f53346227d74b38e6cd2553c4c18de1e64faac585de490eccbd3ab86ba0885bdac42ed4478bc6b0 +"bn.js@npm:4.11.6": + version: 4.11.6 + resolution: "bn.js@npm:4.11.6" + checksum: db23047bf06fdf9cf74401c8e76bca9f55313c81df382247d2c753868b368562e69171716b81b7038ada8860af18346fd4bcd1cf9d4963f923fe8e54e61cb58a languageName: node linkType: hard -"babel-messages@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-messages@npm:6.23.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: c8075c17587a33869e1a5bd0a5b73bbe395b68188362dacd5418debbc7c8fd784bcd3295e81ee7e410dc2c2655755add6af03698c522209f6a68334c15e6d6ca +"bn.js@npm:^4.0.0, bn.js@npm:^4.11.0, bn.js@npm:^4.11.1, bn.js@npm:^4.11.8, bn.js@npm:^4.11.9": + version: 4.12.0 + resolution: "bn.js@npm:4.12.0" + checksum: 39afb4f15f4ea537b55eaf1446c896af28ac948fdcf47171961475724d1bb65118cca49fa6e3d67706e4790955ec0e74de584e45c8f1ef89f46c812bee5b5a12 languageName: node linkType: hard -"babel-plugin-check-es2015-constants@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-check-es2015-constants@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 39168cb4ff078911726bfaf9d111d1e18f3e99d8b6f6101d343249b28346c3869e415c97fe7e857e7f34b913f8a052634b2b9dcfb4c0272e5f64ed22df69c735 +"bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 languageName: node linkType: hard -"babel-plugin-syntax-async-functions@npm:^6.8.0": - version: 6.13.0 - resolution: "babel-plugin-syntax-async-functions@npm:6.13.0" - checksum: e982d9756869fa83eb6a4502490a90b0d31e8a41e2ee582045934f022ac8ff5fa6a3386366976fab3a391d5a7ab8ea5f9da623f35ed8ab328b8ab6d9b2feb1d3 +"boxen@npm:^5.1.2": + version: 5.1.2 + resolution: "boxen@npm:5.1.2" + dependencies: + ansi-align: ^3.0.0 + camelcase: ^6.2.0 + chalk: ^4.1.0 + cli-boxes: ^2.2.1 + string-width: ^4.2.2 + type-fest: ^0.20.2 + widest-line: ^3.1.0 + wrap-ansi: ^7.0.0 + checksum: 82d03e42a72576ff235123f17b7c505372fe05c83f75f61e7d4fa4bcb393897ec95ce766fecb8f26b915f0f7a7227d66e5ec7cef43f5b2bd9d3aeed47ec55877 languageName: node linkType: hard -"babel-plugin-syntax-exponentiation-operator@npm:^6.8.0": - version: 6.13.0 - resolution: "babel-plugin-syntax-exponentiation-operator@npm:6.13.0" - checksum: cbcb3aeae7005240325f72d55c3c90575033123e8a1ddfa6bf9eac4ee7e246c2a23f5b5ab1144879590d947a3ed1d88838169d125e5d7c4f53678526482b020e +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: ^1.0.0 + concat-map: 0.0.1 + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 languageName: node linkType: hard -"babel-plugin-syntax-trailing-function-commas@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-syntax-trailing-function-commas@npm:6.22.0" - checksum: d8b9039ded835bb128e8e14eeeb6e0ac2a876b85250924bdc3a8dc2a6984d3bfade4de04d40fb15ea04a86d561ac280ae0d7306d7d4ef7a8c52c43b6a23909c6 +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: ^1.0.0 + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 languageName: node linkType: hard -"babel-plugin-transform-async-to-generator@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-async-to-generator@npm:6.24.1" +"braces@npm:^3.0.3, braces@npm:~3.0.2": + version: 3.0.3 + resolution: "braces@npm:3.0.3" dependencies: - babel-helper-remap-async-to-generator: ^6.24.1 - babel-plugin-syntax-async-functions: ^6.8.0 - babel-runtime: ^6.22.0 - checksum: ffe8b4b2ed6db1f413ede385bd1a36f39e02a64ed79ce02779440049af75215c98f8debdc70eb01430bfd889f792682b0136576fe966f7f9e1b30e2a54695a8d + fill-range: ^7.1.1 + checksum: b95aa0b3bd909f6cd1720ffcf031aeaf46154dd88b4da01f9a1d3f7ea866a79eba76a6d01cbc3c422b2ee5cdc39a4f02491058d5df0d7bf6e6a162a832df1f69 languageName: node linkType: hard -"babel-plugin-transform-es2015-arrow-functions@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-arrow-functions@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 746e2be0fed20771c07f0984ba79ef0bab37d6e98434267ec96cef57272014fe53a180bfb9047bf69ed149d367a2c97baad54d6057531cd037684f371aab2333 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-block-scoped-functions@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-block-scoped-functions@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: f251611f723d94b4068d2a873a2783e019bd81bd7144cfdbcfc31ef166f4d82fa2f1efba64342ba2630dab93a2b12284067725c0aa08315712419a2bc3b92a75 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-block-scoping@npm:^6.23.0": - version: 6.26.0 - resolution: "babel-plugin-transform-es2015-block-scoping@npm:6.26.0" - dependencies: - babel-runtime: ^6.26.0 - babel-template: ^6.26.0 - babel-traverse: ^6.26.0 - babel-types: ^6.26.0 - lodash: ^4.17.4 - checksum: 5e4dee33bf4aab0ce7751a9ae845c25d3bf03944ffdfc8d784e1de2123a3eec19657dd59274c9969461757f5e2ab75c517e978bafe5309a821a41e278ad38a63 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-classes@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-classes@npm:6.24.1" - dependencies: - babel-helper-define-map: ^6.24.1 - babel-helper-function-name: ^6.24.1 - babel-helper-optimise-call-expression: ^6.24.1 - babel-helper-replace-supers: ^6.24.1 - babel-messages: ^6.23.0 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: 999392b47a83cf9297e49fbde00bc9b15fb6d71bc041f7b3d621ac45361486ec4b66f55c47f98dca6c398ceaa8bfc9f3c21257854822c4523e7475a92e6c000a - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-computed-properties@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-computed-properties@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - checksum: 34e466bfd4b021aa3861db66cf10a9093fa6a4fcedbc8c82a55f6ca1fcbd212a9967f2df6c5f9e9a20046fa43c8967633a476f2bbc15cb8d3769cbba948a5c16 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-destructuring@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-destructuring@npm:6.23.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 1343d27f09846e6e1e48da7b83d0d4f2d5571559c468ad8ad4c3715b8ff3e21b2d553e90ad420dc6840de260b7f3b9f9c057606d527e3d838a52a3a7c5fffdbe - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-duplicate-keys@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-duplicate-keys@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 756a7a13517c3e80c8312137b9872b9bc32fbfbb905e9f1e45bf321e2b464d0e6a6e6deca22c61b62377225bd8136b73580897cccb394995d6e00bc8ce882ba4 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-for-of@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-for-of@npm:6.23.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 0124e320c32b25de84ddaba951a6f0ad031fa5019de54de32bd317d2a97b3f967026008f32e8c88728330c1cce7c4f1d0ecb15007020d50bd5ca1438a882e205 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-function-name@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-function-name@npm:6.24.1" - dependencies: - babel-helper-function-name: ^6.24.1 - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 629ecd824d53ec973a3ef85e74d9fd8c710203084ca2f7ac833879ddfa3b83a28f0270fe2ee5f3b8c078bb4b3e4b843173a646a7cd4abc49e8c1c563d31fb711 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-literals@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-literals@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 40e270580a0236990f2555f5dc7ae24b4db9f4709ca455ed1a6724b0078592482274be7448579b14122bd06481641a38e7b2e48d0b49b8c81c88e154a26865b4 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-modules-amd@npm:^6.22.0, babel-plugin-transform-es2015-modules-amd@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-amd@npm:6.24.1" - dependencies: - babel-plugin-transform-es2015-modules-commonjs: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - checksum: 084c7a1ef3bd0b2b9f4851b27cfb65f8ea1408349af05b4d88f994c23844a0754abfa4799bbc5f3f0ec94232b3a54a2e46d7f1dff1bdd40fa66a46f645197dfa - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-modules-commonjs@npm:^6.23.0, babel-plugin-transform-es2015-modules-commonjs@npm:^6.24.1": - version: 6.26.2 - resolution: "babel-plugin-transform-es2015-modules-commonjs@npm:6.26.2" - dependencies: - babel-plugin-transform-strict-mode: ^6.24.1 - babel-runtime: ^6.26.0 - babel-template: ^6.26.0 - babel-types: ^6.26.0 - checksum: 9cd93a84037855c1879bcc100229bee25b44c4805a9a9f040e8927f772c4732fa17a0706c81ea0db77b357dd9baf84388eec03ceb36597932c48fe32fb3d4171 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-modules-systemjs@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-systemjs@npm:6.24.1" - dependencies: - babel-helper-hoist-variables: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - checksum: b34877e201d7b4d293d87c04962a3575fe7727a9593e99ce3a7f8deea3da8883a08bd87a6a12927083ac26f47f6944a31cdbfe3d6eb4d18dd884cb2d304ee943 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-modules-umd@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-modules-umd@npm:6.24.1" - dependencies: - babel-plugin-transform-es2015-modules-amd: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - checksum: 735857b9f2ad0c41ceda31a1594fe2a063025f4428f9e243885a437b5bd415aca445a5e8495ff34b7120617735b1c3a2158033f0be23f1f5a90e655fff742a01 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-object-super@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-object-super@npm:6.24.1" - dependencies: - babel-helper-replace-supers: ^6.24.1 - babel-runtime: ^6.22.0 - checksum: 97b2968f699ac94cb55f4f1e7ea53dc9e4264ec99cab826f40f181da9f6db5980cd8b4985f05c7b6f1e19fbc31681e6e63894dfc5ecf4b3a673d736c4ef0f9db - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-parameters@npm:^6.23.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-parameters@npm:6.24.1" - dependencies: - babel-helper-call-delegate: ^6.24.1 - babel-helper-get-function-arity: ^6.24.1 - babel-runtime: ^6.22.0 - babel-template: ^6.24.1 - babel-traverse: ^6.24.1 - babel-types: ^6.24.1 - checksum: bb6c047dc10499be8ccebdffac22c77f14aee5d3106da8f2e96c801d2746403c809d8c6922e8ebd2eb31d8827b4bb2321ba43378fcdc9dca206417bb345c4f93 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-shorthand-properties@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-shorthand-properties@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 9302c5de158a28432e932501a783560094c624c3659f4e0a472b6b2e9d6e8ab2634f82ef74d3e75363d46ccff6aad119267dbc34f67464c70625e24a651ad9e5 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-spread@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-spread@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 8694a8a7802d905503194ab81c155354b36d39fc819ad2148f83146518dd37d2c6926c8568712f5aa890169afc9353fd4bcc49397959c6dc9da3480b449c0ae9 - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-sticky-regex@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-sticky-regex@npm:6.24.1" - dependencies: - babel-helper-regex: ^6.24.1 - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: d9c45401caf0d74779a1170e886976d4c865b7de2e90dfffc7557481b9e73b6e37e9f1028aa07b813896c4df88f4d7e89968249a74547c7875e6c499c90c801d - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-template-literals@npm:^6.22.0": - version: 6.22.0 - resolution: "babel-plugin-transform-es2015-template-literals@npm:6.22.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 4fad2b7b383a2e784858ee7bf837419ee8ff9602afe218e1472f8c33a0c008f01d06f23ff2f2322fb23e1ed17e37237a818575fe88ecc5417d85331973b0ea4d - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-typeof-symbol@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-plugin-transform-es2015-typeof-symbol@npm:6.23.0" - dependencies: - babel-runtime: ^6.22.0 - checksum: 68a1609c6abcddf5f138c56bafcd9fad7c6b3b404fe40910148ab70eb21d6c7807a343a64eb81ce45daf4b70c384c528c55fad45e0d581e4b09efa4d574a6a1b - languageName: node - linkType: hard - -"babel-plugin-transform-es2015-unicode-regex@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-es2015-unicode-regex@npm:6.24.1" - dependencies: - babel-helper-regex: ^6.24.1 - babel-runtime: ^6.22.0 - regexpu-core: ^2.0.0 - checksum: 739ddb02e5f77904f83ea45323c9a636e3aed34b2a49c7c68208b5f2834eecb6b655e772f870f16a7aaf09ac8219f754ad69d61741d088f5b681d13cda69265d - languageName: node - linkType: hard - -"babel-plugin-transform-exponentiation-operator@npm:^6.22.0": - version: 6.24.1 - resolution: "babel-plugin-transform-exponentiation-operator@npm:6.24.1" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor: ^6.24.1 - babel-plugin-syntax-exponentiation-operator: ^6.8.0 - babel-runtime: ^6.22.0 - checksum: 533ad53ba2cd6ff3c0f751563e1beea429c620038dc2efeeb8348ab4752ebcc95d1521857abfd08047400f1921b2d4df5e0cd266e65ddbe4c3edc58b9ad6fd3c - languageName: node - linkType: hard - -"babel-plugin-transform-regenerator@npm:^6.22.0": - version: 6.26.0 - resolution: "babel-plugin-transform-regenerator@npm:6.26.0" - dependencies: - regenerator-transform: ^0.10.0 - checksum: 41a51d8f692bf4a5cbd705fa70f3cb6abebae66d9ba3dccfb5921da262f8c30f630e1fe9f7b132e29b96fe0d99385a801f6aa204278c5bd0af4284f7f93a665a - languageName: node - linkType: hard - -"babel-plugin-transform-strict-mode@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-plugin-transform-strict-mode@npm:6.24.1" - dependencies: - babel-runtime: ^6.22.0 - babel-types: ^6.24.1 - checksum: 32d70ce9d8c8918a6a840e46df03dfe1e265eb9b25df5a800fedb5065ef1b4b5f24d7c62d92fca0e374db8b0b9b6f84e68edd02ad21883d48f608583ec29f638 - languageName: node - linkType: hard - -"babel-preset-env@npm:^1.7.0": - version: 1.7.0 - resolution: "babel-preset-env@npm:1.7.0" - dependencies: - babel-plugin-check-es2015-constants: ^6.22.0 - babel-plugin-syntax-trailing-function-commas: ^6.22.0 - babel-plugin-transform-async-to-generator: ^6.22.0 - babel-plugin-transform-es2015-arrow-functions: ^6.22.0 - babel-plugin-transform-es2015-block-scoped-functions: ^6.22.0 - babel-plugin-transform-es2015-block-scoping: ^6.23.0 - babel-plugin-transform-es2015-classes: ^6.23.0 - babel-plugin-transform-es2015-computed-properties: ^6.22.0 - babel-plugin-transform-es2015-destructuring: ^6.23.0 - babel-plugin-transform-es2015-duplicate-keys: ^6.22.0 - babel-plugin-transform-es2015-for-of: ^6.23.0 - babel-plugin-transform-es2015-function-name: ^6.22.0 - babel-plugin-transform-es2015-literals: ^6.22.0 - babel-plugin-transform-es2015-modules-amd: ^6.22.0 - babel-plugin-transform-es2015-modules-commonjs: ^6.23.0 - babel-plugin-transform-es2015-modules-systemjs: ^6.23.0 - babel-plugin-transform-es2015-modules-umd: ^6.23.0 - babel-plugin-transform-es2015-object-super: ^6.22.0 - babel-plugin-transform-es2015-parameters: ^6.23.0 - babel-plugin-transform-es2015-shorthand-properties: ^6.22.0 - babel-plugin-transform-es2015-spread: ^6.22.0 - babel-plugin-transform-es2015-sticky-regex: ^6.22.0 - babel-plugin-transform-es2015-template-literals: ^6.22.0 - babel-plugin-transform-es2015-typeof-symbol: ^6.23.0 - babel-plugin-transform-es2015-unicode-regex: ^6.22.0 - babel-plugin-transform-exponentiation-operator: ^6.22.0 - babel-plugin-transform-regenerator: ^6.22.0 - browserslist: ^3.2.6 - invariant: ^2.2.2 - semver: ^5.3.0 - checksum: 6e459a6c76086a2a377707680148b94c3d0aba425b039b427ca01171ebada7f5db5d336b309548462f6ba015e13176a4724f912875c15084d4aa88d77020d185 - languageName: node - linkType: hard - -"babel-register@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-register@npm:6.26.0" - dependencies: - babel-core: ^6.26.0 - babel-runtime: ^6.26.0 - core-js: ^2.5.0 - home-or-tmp: ^2.0.0 - lodash: ^4.17.4 - mkdirp: ^0.5.1 - source-map-support: ^0.4.15 - checksum: 75d5fe060e4850dbdbd5f56db2928cd0b6b6c93a65ba5f2a991465af4dc3f4adf46d575138f228b2169b1e25e3b4a7cdd16515a355fea41b873321bf56467583 - languageName: node - linkType: hard - -"babel-runtime@npm:^6.18.0, babel-runtime@npm:^6.22.0, babel-runtime@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-runtime@npm:6.26.0" - dependencies: - core-js: ^2.4.0 - regenerator-runtime: ^0.11.0 - checksum: 8aeade94665e67a73c1ccc10f6fd42ba0c689b980032b70929de7a6d9a12eb87ef51902733f8fefede35afea7a5c3ef7e916a64d503446c1eedc9e3284bd3d50 - languageName: node - linkType: hard - -"babel-template@npm:^6.24.1, babel-template@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-template@npm:6.26.0" - dependencies: - babel-runtime: ^6.26.0 - babel-traverse: ^6.26.0 - babel-types: ^6.26.0 - babylon: ^6.18.0 - lodash: ^4.17.4 - checksum: 028dd57380f09b5641b74874a19073c53c4fb3f1696e849575aae18f8c80eaf21db75209057db862f3b893ce2cd9b795d539efa591b58f4a0fb011df0a56fbed - languageName: node - linkType: hard - -"babel-traverse@npm:^6.24.1, babel-traverse@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-traverse@npm:6.26.0" - dependencies: - babel-code-frame: ^6.26.0 - babel-messages: ^6.23.0 - babel-runtime: ^6.26.0 - babel-types: ^6.26.0 - babylon: ^6.18.0 - debug: ^2.6.8 - globals: ^9.18.0 - invariant: ^2.2.2 - lodash: ^4.17.4 - checksum: fca037588d2791ae0409f1b7aa56075b798699cccc53ea04d82dd1c0f97b9e7ab17065f7dd3ecd69101d7874c9c8fd5e0f88fa53abbae1fe94e37e6b81ebcb8d - languageName: node - linkType: hard - -"babel-types@npm:^6.19.0, babel-types@npm:^6.24.1, babel-types@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-types@npm:6.26.0" - dependencies: - babel-runtime: ^6.26.0 - esutils: ^2.0.2 - lodash: ^4.17.4 - to-fast-properties: ^1.0.3 - checksum: d16b0fa86e9b0e4c2623be81d0a35679faff24dd2e43cde4ca58baf49f3e39415a011a889e6c2259ff09e1228e4c3a3db6449a62de59e80152fe1ce7398fde76 - languageName: node - linkType: hard - -"babelify@npm:^7.3.0": - version: 7.3.0 - resolution: "babelify@npm:7.3.0" - dependencies: - babel-core: ^6.0.14 - object-assign: ^4.0.0 - checksum: 4e169606ed0f2ff6f886d2367c72243d36b3b354490ccc916b913f6b4afd14102c91f771d71d485857feb134581dd48702f25431e19b5c7035f474f9898c3c2e - languageName: node - linkType: hard - -"babylon@npm:^6.18.0": - version: 6.18.0 - resolution: "babylon@npm:6.18.0" - bin: - babylon: ./bin/babylon.js - checksum: 0777ae0c735ce1cbfc856d627589ed9aae212b84fb0c03c368b55e6c5d3507841780052808d0ad46e18a2ba516e93d55eeed8cd967f3b2938822dfeccfb2a16d - languageName: node - linkType: hard - -"backoff@npm:^2.5.0": - version: 2.5.0 - resolution: "backoff@npm:2.5.0" - dependencies: - precond: 0.2 - checksum: ccdcf2a26acd9379d0d4f09e3fb3b7ee34dee94f07ab74d1e38b38f89a3675d9f3cbebb142d9c61c655f4c9eb63f1d6ec28cebeb3dc9215efd8fe7cef92725b9 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"base-x@npm:^3.0.2, base-x@npm:^3.0.8": - version: 3.0.9 - resolution: "base-x@npm:3.0.9" - dependencies: - safe-buffer: ^5.0.1 - checksum: 957101d6fd09e1903e846fd8f69fd7e5e3e50254383e61ab667c725866bec54e5ece5ba49ce385128ae48f9ec93a26567d1d5ebb91f4d56ef4a9cc0d5a5481e8 - languageName: node - linkType: hard - -"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 - languageName: node - linkType: hard - -"base64-sol@npm:1.0.1": - version: 1.0.1 - resolution: "base64-sol@npm:1.0.1" - checksum: be0f9e8cf3c744256913223fbae8187773f530cc096e98a77f49ef0bd6cedeb294d15a784e439419f7cb99f07bf85b08999169feafafa1a9e29c3affc0bc6d0a - languageName: node - linkType: hard - -"base@npm:^0.11.1": - version: 0.11.2 - resolution: "base@npm:0.11.2" - dependencies: - cache-base: ^1.0.1 - class-utils: ^0.3.5 - component-emitter: ^1.2.1 - define-property: ^1.0.0 - isobject: ^3.0.1 - mixin-deep: ^1.2.0 - pascalcase: ^0.1.1 - checksum: a4a146b912e27eea8f66d09cb0c9eab666f32ce27859a7dfd50f38cd069a2557b39f16dba1bc2aecb3b44bf096738dd207b7970d99b0318423285ab1b1994edd - languageName: node - linkType: hard - -"bcrypt-pbkdf@npm:^1.0.0": - version: 1.0.2 - resolution: "bcrypt-pbkdf@npm:1.0.2" - dependencies: - tweetnacl: ^0.14.3 - checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291 - languageName: node - linkType: hard - -"bech32@npm:1.1.4": - version: 1.1.4 - resolution: "bech32@npm:1.1.4" - checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b - languageName: node - linkType: hard - -"bignumber.js@npm:^9.0.0": - version: 9.1.2 - resolution: "bignumber.js@npm:9.1.2" - checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf - languageName: node - linkType: hard - -"binary-extensions@npm:^2.0.0": - version: 2.3.0 - resolution: "binary-extensions@npm:2.3.0" - checksum: bcad01494e8a9283abf18c1b967af65ee79b0c6a9e6fcfafebfe91dbe6e0fc7272bafb73389e198b310516ae04f7ad17d79aacf6cb4c0d5d5202a7e2e52c7d98 - languageName: node - linkType: hard - -"binaryen@npm:77.0.0-nightly.20190407": - version: 77.0.0-nightly.20190407 - resolution: "binaryen@npm:77.0.0-nightly.20190407" - bin: - binaryen-as: bin/as.js - binaryen-dis: bin/dis.js - binaryen-opt: bin/opt.js - checksum: 756334720191ec02b28b1fa153009338bee63ead43d5923faa7c651b7b97183b020f2ade712fab45d4cc714cae5bfeef3e8a5624246f87207ee4d847e181f6a9 - languageName: node - linkType: hard - -"bip39@npm:2.5.0": - version: 2.5.0 - resolution: "bip39@npm:2.5.0" - dependencies: - create-hash: ^1.1.0 - pbkdf2: ^3.0.9 - randombytes: ^2.0.1 - safe-buffer: ^5.0.1 - unorm: ^1.3.3 - checksum: 26e83583c43a8430afea1c385328b447005c74ddaf997cd8d3e416057f4968360b08ebf7de32374d605295c3abdd7ddd448d8078a2aa3d951735f4499c23875b - languageName: node - linkType: hard - -"bip39@npm:3.0.4": - version: 3.0.4 - resolution: "bip39@npm:3.0.4" - dependencies: - "@types/node": 11.11.6 - create-hash: ^1.1.0 - pbkdf2: ^3.0.9 - randombytes: ^2.0.1 - checksum: 79ce1600a03d1ba5053bdd4e6323f9463ec340764c7e52918b6c6b9dca81221940f2d9a65656447f108f9bc2c8d9ae8df319cca83bbd1dad63f53ef2768d9bae - languageName: node - linkType: hard - -"bl@npm:^1.0.0": - version: 1.2.3 - resolution: "bl@npm:1.2.3" - dependencies: - readable-stream: ^2.3.5 - safe-buffer: ^5.1.1 - checksum: 123f097989ce2fa9087ce761cd41176aaaec864e28f7dfe5c7dab8ae16d66d9844f849c3ad688eb357e3c5e4f49b573e3c0780bb8bc937206735a3b6f8569a5f - languageName: node - linkType: hard - -"blakejs@npm:^1.1.0": - version: 1.2.1 - resolution: "blakejs@npm:1.2.1" - checksum: d699ba116cfa21d0b01d12014a03e484dd76d483133e6dc9eb415aa70a119f08beb3bcefb8c71840106a00b542cba77383f8be60cd1f0d4589cb8afb922eefbe - languageName: node - linkType: hard - -"blob-to-it@npm:^1.0.1": - version: 1.0.4 - resolution: "blob-to-it@npm:1.0.4" - dependencies: - browser-readablestream-to-it: ^1.0.3 - checksum: e7fbebe5bd7b8187a4a88203639777456596a0cc68372e7b2dbcfbae6dea2b80e2a89522140039b538140bc3e3a6b1e90d1778e725eb8899070f799e61591751 - languageName: node - linkType: hard - -"bluebird@npm:^3.5.0, bluebird@npm:^3.5.2": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef - languageName: node - linkType: hard - -"bn.js@npm:4.11.6": - version: 4.11.6 - resolution: "bn.js@npm:4.11.6" - checksum: db23047bf06fdf9cf74401c8e76bca9f55313c81df382247d2c753868b368562e69171716b81b7038ada8860af18346fd4bcd1cf9d4963f923fe8e54e61cb58a - languageName: node - linkType: hard - -"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.10.0, bn.js@npm:^4.11.0, bn.js@npm:^4.11.1, bn.js@npm:^4.11.6, bn.js@npm:^4.11.8, bn.js@npm:^4.11.9, bn.js@npm:^4.8.0": - version: 4.12.0 - resolution: "bn.js@npm:4.12.0" - checksum: 39afb4f15f4ea537b55eaf1446c896af28ac948fdcf47171961475724d1bb65118cca49fa6e3d67706e4790955ec0e74de584e45c8f1ef89f46c812bee5b5a12 - languageName: node - linkType: hard - -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": - version: 5.2.1 - resolution: "bn.js@npm:5.2.1" - checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 - languageName: node - linkType: hard - -"body-parser@npm:1.20.2, body-parser@npm:^1.16.0": - version: 1.20.2 - resolution: "body-parser@npm:1.20.2" - dependencies: - bytes: 3.1.2 - content-type: ~1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.2 - type-is: ~1.6.18 - unpipe: 1.0.0 - checksum: 14d37ec638ab5c93f6099ecaed7f28f890d222c650c69306872e00b9efa081ff6c596cd9afb9930656aae4d6c4e1c17537bea12bb73c87a217cb3cfea8896737 - languageName: node - linkType: hard - -"boxen@npm:^5.1.2": - version: 5.1.2 - resolution: "boxen@npm:5.1.2" - dependencies: - ansi-align: ^3.0.0 - camelcase: ^6.2.0 - chalk: ^4.1.0 - cli-boxes: ^2.2.1 - string-width: ^4.2.2 - type-fest: ^0.20.2 - widest-line: ^3.1.0 - wrap-ansi: ^7.0.0 - checksum: 82d03e42a72576ff235123f17b7c505372fe05c83f75f61e7d4fa4bcb393897ec95ce766fecb8f26b915f0f7a7227d66e5ec7cef43f5b2bd9d3aeed47ec55877 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: ^1.0.0 - checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"braces@npm:^2.3.1": - version: 2.3.2 - resolution: "braces@npm:2.3.2" - dependencies: - arr-flatten: ^1.1.0 - array-unique: ^0.3.2 - extend-shallow: ^2.0.1 - fill-range: ^4.0.0 - isobject: ^3.0.1 - repeat-element: ^1.1.2 - snapdragon: ^0.8.1 - snapdragon-node: ^2.0.1 - split-string: ^3.0.2 - to-regex: ^3.0.1 - checksum: e30dcb6aaf4a31c8df17d848aa283a65699782f75ad61ae93ec25c9729c66cf58e66f0000a9fec84e4add1135bb7da40f7cb9601b36bebcfa9ca58e8d5c07de0 - languageName: node - linkType: hard - -"braces@npm:^3.0.3, braces@npm:~3.0.2": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: ^7.1.1 - checksum: b95aa0b3bd909f6cd1720ffcf031aeaf46154dd88b4da01f9a1d3f7ea866a79eba76a6d01cbc3c422b2ee5cdc39a4f02491058d5df0d7bf6e6a162a832df1f69 - languageName: node - linkType: hard - -"brorand@npm:^1.0.1, brorand@npm:^1.1.0": - version: 1.1.0 - resolution: "brorand@npm:1.1.0" - checksum: 8a05c9f3c4b46572dec6ef71012b1946db6cae8c7bb60ccd4b7dd5a84655db49fe043ecc6272e7ef1f69dc53d6730b9e2a3a03a8310509a3d797a618cbee52be +"brorand@npm:^1.0.1, brorand@npm:^1.1.0": + version: 1.1.0 + resolution: "brorand@npm:1.1.0" + checksum: 8a05c9f3c4b46572dec6ef71012b1946db6cae8c7bb60ccd4b7dd5a84655db49fe043ecc6272e7ef1f69dc53d6730b9e2a3a03a8310509a3d797a618cbee52be languageName: node linkType: hard @@ -4792,7 +3557,7 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0": +"browserify-aes@npm:^1.2.0": version: 1.2.0 resolution: "browserify-aes@npm:1.2.0" dependencies: @@ -4806,69 +3571,6 @@ __metadata: languageName: node linkType: hard -"browserify-cipher@npm:^1.0.0": - version: 1.0.1 - resolution: "browserify-cipher@npm:1.0.1" - dependencies: - browserify-aes: ^1.0.4 - browserify-des: ^1.0.0 - evp_bytestokey: ^1.0.0 - checksum: 2d8500acf1ee535e6bebe808f7a20e4c3a9e2ed1a6885fff1facbfd201ac013ef030422bec65ca9ece8ffe82b03ca580421463f9c45af6c8415fd629f4118c13 - languageName: node - linkType: hard - -"browserify-des@npm:^1.0.0": - version: 1.0.2 - resolution: "browserify-des@npm:1.0.2" - dependencies: - cipher-base: ^1.0.1 - des.js: ^1.0.0 - inherits: ^2.0.1 - safe-buffer: ^5.1.2 - checksum: b15a3e358a1d78a3b62ddc06c845d02afde6fc826dab23f1b9c016e643e7b1fda41de628d2110b712f6a44fb10cbc1800bc6872a03ddd363fb50768e010395b7 - languageName: node - linkType: hard - -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.1.0": - version: 4.1.0 - resolution: "browserify-rsa@npm:4.1.0" - dependencies: - bn.js: ^5.0.0 - randombytes: ^2.0.1 - checksum: 155f0c135873efc85620571a33d884aa8810e40176125ad424ec9d85016ff105a07f6231650914a760cca66f29af0494087947b7be34880dd4599a0cd3c38e54 - languageName: node - linkType: hard - -"browserify-sign@npm:^4.0.0": - version: 4.2.3 - resolution: "browserify-sign@npm:4.2.3" - dependencies: - bn.js: ^5.2.1 - browserify-rsa: ^4.1.0 - create-hash: ^1.2.0 - create-hmac: ^1.1.7 - elliptic: ^6.5.5 - hash-base: ~3.0 - inherits: ^2.0.4 - parse-asn1: ^5.1.7 - readable-stream: ^2.3.8 - safe-buffer: ^5.2.1 - checksum: 403a8061d229ae31266670345b4a7c00051266761d2c9bbeb68b1a9bcb05f68143b16110cf23a171a5d6716396a1f41296282b3e73eeec0a1871c77f0ff4ee6b - languageName: node - linkType: hard - -"browserslist@npm:^3.2.6": - version: 3.2.8 - resolution: "browserslist@npm:3.2.8" - dependencies: - caniuse-lite: ^1.0.30000844 - electron-to-chromium: ^1.3.47 - bin: - browserslist: ./cli.js - checksum: 74d9ab1089a3813f54a7c4f9f6612faa6256799c8e42c7e00e4aae626c17f199049a01707a525a05b1673cd1493936583e51aad295e25249166e7e8fbd0273ba - languageName: node - linkType: hard - "bs58@npm:^4.0.0": version: 4.0.1 resolution: "bs58@npm:4.0.1" @@ -4920,13 +3622,6 @@ __metadata: languageName: node linkType: hard -"buffer-to-arraybuffer@npm:^0.0.5": - version: 0.0.5 - resolution: "buffer-to-arraybuffer@npm:0.0.5" - checksum: b2e6493a6679e03d0e0e146b4258b9a6d92649d528d8fc4a74423b77f0d4f9398c9f965f3378d1683a91738054bae2761196cfe233f41ab3695126cb58cb25f9 - languageName: node - linkType: hard - "buffer-xor@npm:^1.0.3": version: 1.0.3 resolution: "buffer-xor@npm:1.0.3" @@ -4954,7 +3649,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.0.5, buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0": +"buffer@npm:^5.5.0, buffer@npm:^5.6.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -4984,16 +3679,6 @@ __metadata: languageName: node linkType: hard -"bufferutil@npm:^4.0.1": - version: 4.0.8 - resolution: "bufferutil@npm:4.0.8" - dependencies: - node-gyp: latest - node-gyp-build: ^4.3.0 - checksum: 7e9a46f1867dca72fda350966eb468eca77f4d623407b0650913fadf73d5750d883147d6e5e21c56f9d3b0bdc35d5474e80a600b9f31ec781315b4d2469ef087 - languageName: node - linkType: hard - "builtins@npm:^5.0.1": version: 5.1.0 resolution: "builtins@npm:5.1.0" @@ -5010,25 +3695,6 @@ __metadata: languageName: node linkType: hard -"bytewise-core@npm:^1.2.2": - version: 1.2.3 - resolution: "bytewise-core@npm:1.2.3" - dependencies: - typewise-core: ^1.2 - checksum: e0d28fb7ff5bb6fd9320eef31c6b37e98da3b9a24d9893e2c17e0ee544457e0c76c2d3fc642c99d82daa0f18dcd49e7dce8dcc338711200e9ced79107cb78e8e - languageName: node - linkType: hard - -"bytewise@npm:~1.1.0": - version: 1.1.0 - resolution: "bytewise@npm:1.1.0" - dependencies: - bytewise-core: ^1.2.2 - typewise: ^1.0.3 - checksum: 20d7387ecf8c29adc4740e626fb02eaa27f34ae4c5ca881657d403e792730c0625ba4fed824462b3ddb7d3ebe41b7abbfe24f1cd3bf07cecc5a631f154d2d8d2 - languageName: node - linkType: hard - "cacache@npm:^18.0.0": version: 18.0.3 resolution: "cacache@npm:18.0.3" @@ -5049,71 +3715,7 @@ __metadata: languageName: node linkType: hard -"cache-base@npm:^1.0.1": - version: 1.0.1 - resolution: "cache-base@npm:1.0.1" - dependencies: - collection-visit: ^1.0.0 - component-emitter: ^1.2.1 - get-value: ^2.0.6 - has-value: ^1.0.0 - isobject: ^3.0.1 - set-value: ^2.0.0 - to-object-path: ^0.3.0 - union-value: ^1.0.0 - unset-value: ^1.0.0 - checksum: 9114b8654fe2366eedc390bad0bcf534e2f01b239a888894e2928cb58cdc1e6ea23a73c6f3450dcfd2058aa73a8a981e723cd1e7c670c047bf11afdc65880107 - languageName: node - linkType: hard - -"cacheable-lookup@npm:^5.0.3": - version: 5.0.4 - resolution: "cacheable-lookup@npm:5.0.4" - checksum: 763e02cf9196bc9afccacd8c418d942fc2677f22261969a4c2c2e760fa44a2351a81557bd908291c3921fe9beb10b976ba8fa50c5ca837c5a0dd945f16468f2d - languageName: node - linkType: hard - -"cacheable-request@npm:^6.0.0": - version: 6.1.0 - resolution: "cacheable-request@npm:6.1.0" - dependencies: - clone-response: ^1.0.2 - get-stream: ^5.1.0 - http-cache-semantics: ^4.0.0 - keyv: ^3.0.0 - lowercase-keys: ^2.0.0 - normalize-url: ^4.1.0 - responselike: ^1.0.2 - checksum: b510b237b18d17e89942e9ee2d2a077cb38db03f12167fd100932dfa8fc963424bfae0bfa1598df4ae16c944a5484e43e03df8f32105b04395ee9495e9e4e9f1 - languageName: node - linkType: hard - -"cacheable-request@npm:^7.0.2": - version: 7.0.4 - resolution: "cacheable-request@npm:7.0.4" - dependencies: - clone-response: ^1.0.2 - get-stream: ^5.1.0 - http-cache-semantics: ^4.0.0 - keyv: ^4.0.0 - lowercase-keys: ^2.0.0 - normalize-url: ^6.0.1 - responselike: ^2.0.0 - checksum: 0de9df773fd4e7dd9bd118959878f8f2163867e2e1ab3575ffbecbe6e75e80513dd0c68ba30005e5e5a7b377cc6162bbc00ab1db019bb4e9cb3c2f3f7a6f1ee4 - languageName: node - linkType: hard - -"cachedown@npm:1.0.0": - version: 1.0.0 - resolution: "cachedown@npm:1.0.0" - dependencies: - abstract-leveldown: ^2.4.1 - lru-cache: ^3.2.0 - checksum: ffd229839ca7efbfa14e35321fb8df444421e192bdf7be16048a303d2a24f3ed86cbe6c7a8cca91761423e4c53c3ed1098d337bbb9d3448801d4792172b4ab3e - languageName: node - linkType: hard - -"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7, call-bind@npm:~1.0.2": +"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": version: 1.0.7 resolution: "call-bind@npm:1.0.7" dependencies: @@ -5133,13 +3735,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^3.0.0": - version: 3.0.0 - resolution: "camelcase@npm:3.0.0" - checksum: ae4fe1c17c8442a3a345a6b7d2393f028ab7a7601af0c352ad15d1ab97ca75112e19e29c942b2a214898e160194829b68923bce30e018d62149c6d84187f1673 - languageName: node - linkType: hard - "camelcase@npm:^5.0.0": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -5154,14 +3749,7 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30000844": - version: 1.0.30001639 - resolution: "caniuse-lite@npm:1.0.30001639" - checksum: 0d9291cc47ffaad5806716bff6fef41eec21f86a448370bc30a72823fcaf24ba5ccb4704841e6a60f078ddf2e9987e3d23f4d3ca0fffc51f6cb0400b7411ad28 - languageName: node - linkType: hard - -"caseless@npm:^0.12.0, caseless@npm:~0.12.0": +"caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751 @@ -5238,20 +3826,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^1.1.3": - version: 1.1.3 - resolution: "chalk@npm:1.1.3" - dependencies: - ansi-styles: ^2.2.1 - escape-string-regexp: ^1.0.2 - has-ansi: ^2.0.0 - strip-ansi: ^3.0.0 - supports-color: ^2.0.0 - checksum: 9d2ea6b98fc2b7878829eec223abcf404622db6c48396a9b9257f6d0ead2acf18231ae368d6a664a83f272b0679158da12e97b5229f794939e555cc574478acd - languageName: node - linkType: hard - -"chalk@npm:^2.1.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.1.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -5295,16 +3870,7 @@ __metadata: languageName: node linkType: hard -"checkpoint-store@npm:^1.1.0": - version: 1.1.0 - resolution: "checkpoint-store@npm:1.1.0" - dependencies: - functional-red-black-tree: ^1.0.1 - checksum: 94e921ccb222c7970615e8b2bcd956dbd52f15a1c397af0447dbdef8ecd32ffe342e394d39e55f2912278a460f3736de777b5b57a5baf229c0a6bd04d2465511 - languageName: node - linkType: hard - -"chokidar@npm:^3.0.2, chokidar@npm:^3.4.0, chokidar@npm:^3.5.3": +"chokidar@npm:^3.0.2, chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" dependencies: @@ -5323,7 +3889,16 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.0.1, chownr@npm:^1.1.4": +"chokidar@npm:^4.0.0": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" + dependencies: + readdirp: ^4.0.1 + checksum: a8765e452bbafd04f3f2fad79f04222dd65f43161488bb6014a41099e6ca18d166af613d59a90771908c1c823efa3f46ba36b86ac50b701c20c1b9908c5fe36e + languageName: node + linkType: hard + +"chownr@npm:^1.0.1": version: 1.1.4 resolution: "chownr@npm:1.1.4" checksum: 115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d @@ -5344,19 +3919,6 @@ __metadata: languageName: node linkType: hard -"cids@npm:^0.7.1": - version: 0.7.5 - resolution: "cids@npm:0.7.5" - dependencies: - buffer: ^5.5.0 - class-is: ^1.1.0 - multibase: ~0.6.0 - multicodec: ^1.0.0 - multihashes: ~0.4.15 - checksum: 54aa031bef76b08a2c934237696a4af2cfc8afb5d2727cb39ab69f6ac142ef312b9a0c6070dc2b4be0a43076d8961339d8bf85287773c647b3d1d25ce203f325 - languageName: node - linkType: hard - "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": version: 1.0.4 resolution: "cipher-base@npm:1.0.4" @@ -5367,25 +3929,6 @@ __metadata: languageName: node linkType: hard -"class-is@npm:^1.1.0": - version: 1.1.0 - resolution: "class-is@npm:1.1.0" - checksum: 49024de3b264fc501a38dd59d8668f1a2b4973fa6fcef6b83d80fe6fe99a2000a8fbea5b50d4607169c65014843c9f6b41a4f8473df806c1b4787b4d47521880 - languageName: node - linkType: hard - -"class-utils@npm:^0.3.5": - version: 0.3.6 - resolution: "class-utils@npm:0.3.6" - dependencies: - arr-union: ^3.1.0 - define-property: ^0.2.5 - isobject: ^3.0.0 - static-extend: ^0.1.1 - checksum: be108900801e639e50f96a7e4bfa8867c753a7750a7603879f3981f8b0a89cba657497a2d5f40cd4ea557ff15d535a100818bb486baf6e26fe5d7872e75f1078 - languageName: node - linkType: hard - "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -5416,20 +3959,6 @@ __metadata: languageName: node linkType: hard -"cli-table3@npm:^0.5.0, cli-table3@npm:~0.5.0": - version: 0.5.1 - resolution: "cli-table3@npm:0.5.1" - dependencies: - colors: ^1.1.2 - object-assign: ^4.1.0 - string-width: ^2.1.1 - dependenciesMeta: - colors: - optional: true - checksum: 3ff8c821440a2a0e655a01f04e5b54a0365b3814676cd93cec2b2b0b9952a08311797ad242a181733fcff714fa7d776f8bb45ad812f296390bfa5ef584fb231d - languageName: node - linkType: hard - "cli-table3@npm:^0.6.3": version: 0.6.5 resolution: "cli-table3@npm:0.6.5" @@ -5443,21 +3972,24 @@ __metadata: languageName: node linkType: hard -"cli-width@npm:^3.0.0": - version: 3.0.0 - resolution: "cli-width@npm:3.0.0" - checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6 +"cli-table3@npm:~0.5.0": + version: 0.5.1 + resolution: "cli-table3@npm:0.5.1" + dependencies: + colors: ^1.1.2 + object-assign: ^4.1.0 + string-width: ^2.1.1 + dependenciesMeta: + colors: + optional: true + checksum: 3ff8c821440a2a0e655a01f04e5b54a0365b3814676cd93cec2b2b0b9952a08311797ad242a181733fcff714fa7d776f8bb45ad812f296390bfa5ef584fb231d languageName: node linkType: hard -"cliui@npm:^3.2.0": - version: 3.2.0 - resolution: "cliui@npm:3.2.0" - dependencies: - string-width: ^1.0.1 - strip-ansi: ^3.0.1 - wrap-ansi: ^2.0.0 - checksum: c68d1dbc3e347bfe79ed19cc7f48007d5edd6cd8438342e32073e0b4e311e3c44e1f4f19221462bc6590de56c2df520e427533a9dde95dee25710bec322746ad +"cli-width@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-width@npm:3.0.0" + checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6 languageName: node linkType: hard @@ -5483,22 +4015,6 @@ __metadata: languageName: node linkType: hard -"clone-response@npm:^1.0.2": - version: 1.0.3 - resolution: "clone-response@npm:1.0.3" - dependencies: - mimic-response: ^1.0.0 - checksum: 4e671cac39b11c60aa8ba0a450657194a5d6504df51bca3fac5b3bd0145c4f8e8464898f87c8406b83232e3bc5cca555f51c1f9c8ac023969ebfbf7f6bdabb2e - languageName: node - linkType: hard - -"clone@npm:2.1.2, clone@npm:^2.0.0": - version: 2.1.2 - resolution: "clone@npm:2.1.2" - checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d - languageName: node - linkType: hard - "clone@npm:^1.0.2": version: 1.0.4 resolution: "clone@npm:1.0.4" @@ -5506,23 +4022,6 @@ __metadata: languageName: node linkType: hard -"code-point-at@npm:^1.0.0": - version: 1.1.0 - resolution: "code-point-at@npm:1.1.0" - checksum: 17d5666611f9b16d64fdf48176d9b7fb1c7d1c1607a189f7e600040a11a6616982876af148230336adb7d8fe728a559f743a4e29db3747e3b1a32fa7f4529681 - languageName: node - linkType: hard - -"collection-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "collection-visit@npm:1.0.0" - dependencies: - map-visit: ^1.0.0 - object-visit: ^1.0.0 - checksum: 15d9658fe6eb23594728346adad5433b86bb7a04fd51bbab337755158722f9313a5376ef479de5b35fbc54140764d0d39de89c339f5d25b959ed221466981da9 - languageName: node - linkType: hard - "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -5555,7 +4054,7 @@ __metadata: languageName: node linkType: hard -"colors@npm:1.4.0, colors@npm:^1.1.2, colors@npm:^1.3.3": +"colors@npm:^1.1.2, colors@npm:^1.3.3": version: 1.4.0 resolution: "colors@npm:1.4.0" checksum: 98aa2c2418ad87dedf25d781be69dc5fc5908e279d9d30c34d8b702e586a0474605b3a189511482b9d5ed0d20c867515d22749537f7bc546256c6014f3ebdcec @@ -5578,19 +4077,6 @@ __metadata: languageName: node linkType: hard -"command-line-args@npm:^4.0.7": - version: 4.0.7 - resolution: "command-line-args@npm:4.0.7" - dependencies: - array-back: ^2.0.0 - find-replace: ^1.0.3 - typical: ^2.6.1 - bin: - command-line-args: bin/cli.js - checksum: 618109143fbca741048d54a5d31a2a5e166fbda318ed1419c1ca66877ce92ed80d6768a52a2e6392eb751f16ca7755d4014ced6f5f858a68d0cbe793bab6e3ee - languageName: node - linkType: hard - "command-line-args@npm:^5.1.1": version: 5.2.1 resolution: "command-line-args@npm:5.2.1" @@ -5615,13 +4101,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:3.0.2": - version: 3.0.2 - resolution: "commander@npm:3.0.2" - checksum: 6d14ad030d1904428139487ed31febcb04c1604db2b8d9fae711f60ee6718828dc0e11602249e91c8a97b0e721e9c6d53edbc166bad3cde1596851d59a8f824d - languageName: node - linkType: hard - "commander@npm:^10.0.0": version: 10.0.1 resolution: "commander@npm:10.0.1" @@ -5650,13 +4129,6 @@ __metadata: languageName: node linkType: hard -"component-emitter@npm:^1.2.1": - version: 1.3.1 - resolution: "component-emitter@npm:1.3.1" - checksum: 94550aa462c7bd5a61c1bc480e28554aa306066930152d1b1844a0dd3845d4e5db7e261ddec62ae184913b3e59b55a2ad84093b9d3596a8f17c341514d6c483d - languageName: node - linkType: hard - "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -5664,7 +4136,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.1, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2, concat-stream@npm:~1.6.2": +"concat-stream@npm:~1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -5676,54 +4148,6 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:0.5.4": - version: 0.5.4 - resolution: "content-disposition@npm:0.5.4" - dependencies: - safe-buffer: 5.2.1 - checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 - languageName: node - linkType: hard - -"content-hash@npm:^2.5.2": - version: 2.5.2 - resolution: "content-hash@npm:2.5.2" - dependencies: - cids: ^0.7.1 - multicodec: ^0.5.5 - multihashes: ^0.4.15 - checksum: 31869e4d137b59d02003df0c0f0ad080744d878ed12a57f7d20b2cfd526d59d6317e9f52fa6e49cba59df7f9ab49ceb96d6a832685b85bae442e0c906f7193be - languageName: node - linkType: hard - -"content-type@npm:~1.0.4, content-type@npm:~1.0.5": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 - languageName: node - linkType: hard - -"convert-source-map@npm:^1.5.1": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 - languageName: node - linkType: hard - -"cookie-signature@npm:1.0.6": - version: 1.0.6 - resolution: "cookie-signature@npm:1.0.6" - checksum: f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a - languageName: node - linkType: hard - -"cookie@npm:0.6.0": - version: 0.6.0 - resolution: "cookie@npm:0.6.0" - checksum: f56a7d32a07db5458e79c726b77e3c2eff655c36792f2b6c58d351fb5f61531e5b1ab7f46987150136e366c65213cbe31729e02a3eaed630c3bf7334635fb410 - languageName: node - linkType: hard - "cookie@npm:^0.4.1": version: 0.4.2 resolution: "cookie@npm:0.4.2" @@ -5731,20 +4155,6 @@ __metadata: languageName: node linkType: hard -"cookiejar@npm:^2.1.1": - version: 2.1.4 - resolution: "cookiejar@npm:2.1.4" - checksum: c4442111963077dc0e5672359956d6556a195d31cbb35b528356ce5f184922b99ac48245ac05ed86cf993f7df157c56da10ab3efdadfed79778a0d9b1b092d5b - languageName: node - linkType: hard - -"copy-descriptor@npm:^0.1.0": - version: 0.1.1 - resolution: "copy-descriptor@npm:0.1.1" - checksum: d4b7b57b14f1d256bb9aa0b479241048afd7f5bcf22035fc7b94e8af757adeae247ea23c1a774fe44869fd5694efba4a969b88d966766c5245fdee59837fe45b - languageName: node - linkType: hard - "core-js-pure@npm:^3.0.1": version: 3.37.1 resolution: "core-js-pure@npm:3.37.1" @@ -5752,13 +4162,6 @@ __metadata: languageName: node linkType: hard -"core-js@npm:^2.4.0, core-js@npm:^2.5.0": - version: 2.6.12 - resolution: "core-js@npm:2.6.12" - checksum: 44fa9934a85f8c78d61e0c8b7b22436330471ffe59ec5076fe7f324d6e8cf7f824b14b1c81ca73608b13bdb0fef035bd820989bf059767ad6fa13123bb8bd016 - languageName: node - linkType: hard - "core-util-is@npm:1.0.2": version: 1.0.2 resolution: "core-util-is@npm:1.0.2" @@ -5773,16 +4176,6 @@ __metadata: languageName: node linkType: hard -"cors@npm:^2.8.1": - version: 2.8.5 - resolution: "cors@npm:2.8.5" - dependencies: - object-assign: ^4 - vary: ^1 - checksum: ced838404ccd184f61ab4fdc5847035b681c90db7ac17e428f3d81d69e2989d2b680cc254da0e2554f5ed4f8a341820a1ce3d1c16b499f6e2f47a1b9b07b5006 - languageName: node - linkType: hard - "cosmiconfig@npm:6.0.0": version: 6.0.0 resolution: "cosmiconfig@npm:6.0.0" @@ -5822,16 +4215,6 @@ __metadata: languageName: node linkType: hard -"create-ecdh@npm:^4.0.0": - version: 4.0.4 - resolution: "create-ecdh@npm:4.0.4" - dependencies: - bn.js: ^4.1.0 - elliptic: ^6.5.3 - checksum: 0dd7fca9711d09e152375b79acf1e3f306d1a25ba87b8ff14c2fd8e68b83aafe0a7dd6c4e540c9ffbdd227a5fa1ad9b81eca1f233c38bb47770597ba247e614b - languageName: node - linkType: hard - "create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": version: 1.2.0 resolution: "create-hash@npm:1.2.0" @@ -5845,7 +4228,7 @@ __metadata: languageName: node linkType: hard -"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": +"create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": version: 1.1.7 resolution: "create-hmac@npm:1.1.7" dependencies: @@ -5866,16 +4249,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^2.1.0, cross-fetch@npm:^2.1.1": - version: 2.2.6 - resolution: "cross-fetch@npm:2.2.6" - dependencies: - node-fetch: ^2.6.7 - whatwg-fetch: ^2.0.4 - checksum: df9c6728b314ff96022dca468a3d2a05b4546cd318d82a7e1f1445e7160472d39029bccbe5f20d319b8ba3793930592b0b956244aef6a87a133fbcfed85fc8ca - languageName: node - linkType: hard - "cross-spawn@npm:^6.0.0, cross-spawn@npm:^6.0.5": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" @@ -5907,35 +4280,6 @@ __metadata: languageName: node linkType: hard -"crypto-browserify@npm:3.12.0": - version: 3.12.0 - resolution: "crypto-browserify@npm:3.12.0" - dependencies: - browserify-cipher: ^1.0.0 - browserify-sign: ^4.0.0 - create-ecdh: ^4.0.0 - create-hash: ^1.1.0 - create-hmac: ^1.1.0 - diffie-hellman: ^5.0.0 - inherits: ^2.0.1 - pbkdf2: ^3.0.3 - public-encrypt: ^4.0.0 - randombytes: ^2.0.0 - randomfill: ^1.0.3 - checksum: c1609af82605474262f3eaa07daa0b2140026bd264ab316d4bf1170272570dbe02f0c49e29407fe0d3634f96c507c27a19a6765fb856fed854a625f9d15618e2 - languageName: node - linkType: hard - -"d@npm:1, d@npm:^1.0.1, d@npm:^1.0.2": - version: 1.0.2 - resolution: "d@npm:1.0.2" - dependencies: - es5-ext: ^0.10.64 - type: ^2.7.2 - checksum: 775db1e8ced6707cddf64a5840522fcf5475d38ef49a5d615be0ac47f86ef64d15f5a73de1522b09327cc466d4dc35ea83dbfeed456f7a0fdcab138deb800355 - languageName: node - linkType: hard - "dashdash@npm:^1.12.0": version: 1.14.1 resolution: "dashdash@npm:1.14.1" @@ -5985,24 +4329,6 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.8, debug@npm:^2.6.9": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: 2.0.0 - checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 - languageName: node - linkType: hard - -"debug@npm:3.2.6": - version: 3.2.6 - resolution: "debug@npm:3.2.6" - dependencies: - ms: ^2.1.1 - checksum: 07bc8b3a13ef3cfa6c06baf7871dfb174c291e5f85dbf566f086620c16b9c1a0e93bb8f1935ebbd07a683249e7e30286f2966e2ef461e8fd17b1b60732062d6b - languageName: node - linkType: hard - "debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.5 resolution: "debug@npm:4.3.5" @@ -6027,6 +4353,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:^2.2.0": + version: 2.6.9 + resolution: "debug@npm:2.6.9" + dependencies: + ms: 2.0.0 + checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 + languageName: node + linkType: hard + "debug@npm:^3.1.0, debug@npm:^3.2.6, debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" @@ -6036,7 +4371,7 @@ __metadata: languageName: node linkType: hard -"decamelize@npm:^1.1.1, decamelize@npm:^1.2.0": +"decamelize@npm:^1.2.0": version: 1.2.0 resolution: "decamelize@npm:1.2.0" checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa @@ -6050,31 +4385,6 @@ __metadata: languageName: node linkType: hard -"decode-uri-component@npm:^0.2.0": - version: 0.2.2 - resolution: "decode-uri-component@npm:0.2.2" - checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 - languageName: node - linkType: hard - -"decompress-response@npm:^3.3.0": - version: 3.3.0 - resolution: "decompress-response@npm:3.3.0" - dependencies: - mimic-response: ^1.0.0 - checksum: 952552ac3bd7de2fc18015086b09468645c9638d98a551305e485230ada278c039c91116e946d07894b39ee53c0f0d5b6473f25a224029344354513b412d7380 - languageName: node - linkType: hard - -"decompress-response@npm:^6.0.0": - version: 6.0.0 - resolution: "decompress-response@npm:6.0.0" - dependencies: - mimic-response: ^3.1.0 - checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 - languageName: node - linkType: hard - "deep-eql@npm:^4.0.1, deep-eql@npm:^4.1.3": version: 4.1.4 resolution: "deep-eql@npm:4.1.4" @@ -6084,20 +4394,6 @@ __metadata: languageName: node linkType: hard -"deep-equal@npm:~1.1.1": - version: 1.1.2 - resolution: "deep-equal@npm:1.1.2" - dependencies: - is-arguments: ^1.1.1 - is-date-object: ^1.0.5 - is-regex: ^1.1.4 - object-is: ^1.1.5 - object-keys: ^1.1.1 - regexp.prototype.flags: ^1.5.1 - checksum: 2d50f27fff785fb272cdef038ee5365ee5a30ab1aab053976e6a6add44cc60abd99b38179a46a01ac52c5e54ebb220e8f1a3a1954da20678b79c46ef4d97c9db - languageName: node - linkType: hard - "deep-extend@npm:~0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -6121,39 +4417,6 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^1.0.1": - version: 1.1.3 - resolution: "defer-to-connect@npm:1.1.3" - checksum: 9491b301dcfa04956f989481ba7a43c2231044206269eb4ab64a52d6639ee15b1252262a789eb4239fb46ab63e44d4e408641bae8e0793d640aee55398cb3930 - languageName: node - linkType: hard - -"defer-to-connect@npm:^2.0.0": - version: 2.0.1 - resolution: "defer-to-connect@npm:2.0.1" - checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b - languageName: node - linkType: hard - -"deferred-leveldown@npm:~1.2.1": - version: 1.2.2 - resolution: "deferred-leveldown@npm:1.2.2" - dependencies: - abstract-leveldown: ~2.6.0 - checksum: ad3a26d20dc80c702c85c4795cbb52ef25d8e500728c98098b468c499ca745051e6cc03bd12be97ff38c43466a7895879db76ffb761a75b0f009829d990a0ea9 - languageName: node - linkType: hard - -"deferred-leveldown@npm:~4.0.0": - version: 4.0.2 - resolution: "deferred-leveldown@npm:4.0.2" - dependencies: - abstract-leveldown: ~5.0.0 - inherits: ^2.0.3 - checksum: 6b3649bbb7a2617e08eecdddb516d0bde215bd376a37089df203ad78627f59c424c785afbcbfd3e53488d4f9e5d27d9d126d5645b7da53e8760cc34df2d2f13e - languageName: node - linkType: hard - "deferred-leveldown@npm:~5.3.0": version: 5.3.0 resolution: "deferred-leveldown@npm:5.3.0" @@ -6164,7 +4427,7 @@ __metadata: languageName: node linkType: hard -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.1, define-data-property@npm:^1.1.4": +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" dependencies: @@ -6186,41 +4449,6 @@ __metadata: languageName: node linkType: hard -"define-property@npm:^0.2.5": - version: 0.2.5 - resolution: "define-property@npm:0.2.5" - dependencies: - is-descriptor: ^0.1.0 - checksum: 85af107072b04973b13f9e4128ab74ddfda48ec7ad2e54b193c0ffb57067c4ce5b7786a7b4ae1f24bd03e87c5d18766b094571810b314d7540f86d4354dbd394 - languageName: node - linkType: hard - -"define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "define-property@npm:1.0.0" - dependencies: - is-descriptor: ^1.0.0 - checksum: 5fbed11dace44dd22914035ba9ae83ad06008532ca814d7936a53a09e897838acdad5b108dd0688cc8d2a7cf0681acbe00ee4136cf36743f680d10517379350a - languageName: node - linkType: hard - -"define-property@npm:^2.0.2": - version: 2.0.2 - resolution: "define-property@npm:2.0.2" - dependencies: - is-descriptor: ^1.0.2 - isobject: ^3.0.1 - checksum: 3217ed53fc9eed06ba8da6f4d33e28c68a82e2f2a8ab4d562c4920d8169a166fe7271453675e6c69301466f36a65d7f47edf0cf7f474b9aa52a5ead9c1b13c99 - languageName: node - linkType: hard - -"defined@npm:~1.0.1": - version: 1.0.1 - resolution: "defined@npm:1.0.1" - checksum: b1a852300bdb57f297289b55eafdd0c517afaa3ec8190e78fce91b9d8d0c0369d4505ecbdacfd3d98372e664f4a267d9bd793938d4a8c76209c9d9516fbe2101 - languageName: node - linkType: hard - "delay@npm:^5.0.0": version: 5.0.0 resolution: "delay@npm:5.0.0" @@ -6242,32 +4470,6 @@ __metadata: languageName: node linkType: hard -"des.js@npm:^1.0.0": - version: 1.1.0 - resolution: "des.js@npm:1.1.0" - dependencies: - inherits: ^2.0.1 - minimalistic-assert: ^1.0.0 - checksum: 0e9c1584b70d31e20f20a613fc9ef60fbc6a147dfec9e448a168794a4b97ac04d8dc47ea008f1fa93b0f8aaf7c1ead632a5e59ce1913a6079d2d244c9f5ebe33 - languageName: node - linkType: hard - -"destroy@npm:1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 - languageName: node - linkType: hard - -"detect-indent@npm:^4.0.0": - version: 4.0.0 - resolution: "detect-indent@npm:4.0.0" - dependencies: - repeating: ^2.0.0 - checksum: 328f273915c1610899bc7d4784ce874413d0a698346364cd3ee5d79afba1c5cf4dbc97b85a801e20f4d903c0598bd5096af32b800dfb8696b81464ccb3dfda2c - languageName: node - linkType: hard - "diff@npm:5.0.0": version: 5.0.0 resolution: "diff@npm:5.0.0" @@ -6282,24 +4484,6 @@ __metadata: languageName: node linkType: hard -"diff@npm:^5.0.0": - version: 5.2.0 - resolution: "diff@npm:5.2.0" - checksum: 12b63ca9c36c72bafa3effa77121f0581b4015df18bc16bac1f8e263597735649f1a173c26f7eba17fb4162b073fee61788abe49610e6c70a2641fe1895443fd - languageName: node - linkType: hard - -"diffie-hellman@npm:^5.0.0": - version: 5.0.3 - resolution: "diffie-hellman@npm:5.0.3" - dependencies: - bn.js: ^4.1.0 - miller-rabin: ^4.0.0 - randombytes: ^2.0.0 - checksum: 0e620f322170c41076e70181dd1c24e23b08b47dbb92a22a644f3b89b6d3834b0f8ee19e37916164e5eb1ee26d2aa836d6129f92723995267250a0b541811065 - languageName: node - linkType: hard - "difflib@npm:^0.2.4": version: 0.2.4 resolution: "difflib@npm:0.2.4" @@ -6379,13 +4563,6 @@ __metadata: languageName: node linkType: hard -"dom-walk@npm:^0.1.0": - version: 0.1.2 - resolution: "dom-walk@npm:0.1.2" - checksum: 19eb0ce9c6de39d5e231530685248545d9cd2bd97b2cb3486e0bfc0f2a393a9addddfd5557463a932b52fdfcf68ad2a619020cd2c74a5fe46fbecaa8e80872f3 - languageName: node - linkType: hard - "dotenv@npm:^16.0.1": version: 16.4.5 resolution: "dotenv@npm:16.4.5" @@ -6393,24 +4570,6 @@ __metadata: languageName: node linkType: hard -"dotignore@npm:~0.1.2": - version: 0.1.2 - resolution: "dotignore@npm:0.1.2" - dependencies: - minimatch: ^3.0.4 - bin: - ignored: bin/ignored - checksum: 06bab15e2a2400c6f823a0edbcd73661180f6245a4041a3fe3b9fde4b22ae74b896604df4520a877093f05c656bd080087376c9f605bccdea847664c59910f37 - languageName: node - linkType: hard - -"duplexer3@npm:^0.1.4": - version: 0.1.5 - resolution: "duplexer3@npm:0.1.5" - checksum: e677cb4c48f031ca728601d6a20bf6aed4c629d69ef9643cb89c67583d673c4ec9317cc6427501f38bd8c368d3a18f173987cc02bd99d8cf8fe3d94259a22a20 - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -6428,13 +4587,6 @@ __metadata: languageName: node linkType: hard -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f - languageName: node - linkType: hard - "ejs@npm:^2.6.1": version: 2.7.4 resolution: "ejs@npm:2.7.4" @@ -6451,13 +4603,6 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.3.47": - version: 1.4.815 - resolution: "electron-to-chromium@npm:1.4.815" - checksum: 049fa7eb0c9e46522bfe0cd7d025011987dbd0ac2b7418793786c6a6043af55f4f80556ede6bf0447643b274f622d69833e4557814bd2d98ce31129a6eb01afa - languageName: node - linkType: hard - "elliptic@npm:6.5.4": version: 6.5.4 resolution: "elliptic@npm:6.5.4" @@ -6473,7 +4618,7 @@ __metadata: languageName: node linkType: hard -"elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.3, elliptic@npm:^6.5.4, elliptic@npm:^6.5.5": +"elliptic@npm:^6.5.2, elliptic@npm:^6.5.4": version: 6.5.5 resolution: "elliptic@npm:6.5.5" dependencies: @@ -6516,26 +4661,6 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c - languageName: node - linkType: hard - -"encoding-down@npm:5.0.4, encoding-down@npm:~5.0.0": - version: 5.0.4 - resolution: "encoding-down@npm:5.0.4" - dependencies: - abstract-leveldown: ^5.0.0 - inherits: ^2.0.3 - level-codec: ^9.0.0 - level-errors: ^2.0.0 - xtend: ^4.0.1 - checksum: b8d9d4b058622c11e33d8ec0fb6432194925e109ed8e44e93555406496e8b77b294c8c338dd5ed9ab8d7bc50250a48bb93f9af62ecee3ce8d82f4ef78b2ca880 - languageName: node - linkType: hard - "encoding-down@npm:^6.3.0": version: 6.3.0 resolution: "encoding-down@npm:6.3.0" @@ -6548,7 +4673,7 @@ __metadata: languageName: node linkType: hard -"encoding@npm:^0.1.11, encoding@npm:^0.1.13": +"encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" dependencies: @@ -6617,7 +4742,7 @@ __metadata: languageName: node linkType: hard -"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1": +"error-ex@npm:^1.3.1": version: 1.3.2 resolution: "error-ex@npm:1.3.2" dependencies: @@ -6680,13 +4805,6 @@ __metadata: languageName: node linkType: hard -"es-array-method-boxes-properly@npm:^1.0.0": - version: 1.0.0 - resolution: "es-array-method-boxes-properly@npm:1.0.0" - checksum: 2537fcd1cecf187083890bc6f5236d3a26bf39237433587e5bf63392e88faae929dbba78ff0120681a3f6f81c23fe3816122982c160d63b38c95c830b633b826 - languageName: node - linkType: hard - "es-define-property@npm:^1.0.0": version: 1.0.0 resolution: "es-define-property@npm:1.0.0" @@ -6743,29 +4861,6 @@ __metadata: languageName: node linkType: hard -"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.50, es5-ext@npm:^0.10.62, es5-ext@npm:^0.10.63, es5-ext@npm:^0.10.64, es5-ext@npm:~0.10.14": - version: 0.10.64 - resolution: "es5-ext@npm:0.10.64" - dependencies: - es6-iterator: ^2.0.3 - es6-symbol: ^3.1.3 - esniff: ^2.0.1 - next-tick: ^1.1.0 - checksum: 01179fab0769fdbef213062222f99d0346724dbaccf04b87c0e6ee7f0c97edabf14be647ca1321f0497425ea7145de0fd278d1b3f3478864b8933e7136a5c645 - languageName: node - linkType: hard - -"es6-iterator@npm:^2.0.3": - version: 2.0.3 - resolution: "es6-iterator@npm:2.0.3" - dependencies: - d: 1 - es5-ext: ^0.10.35 - es6-symbol: ^3.1.1 - checksum: 6e48b1c2d962c21dee604b3d9f0bc3889f11ed5a8b33689155a2065d20e3107e2a69cc63a71bd125aeee3a589182f8bbcb5c8a05b6a8f38fa4205671b6d09697 - languageName: node - linkType: hard - "es6-promise@npm:^4.0.3": version: 4.2.8 resolution: "es6-promise@npm:4.2.8" @@ -6782,27 +4877,10 @@ __metadata: languageName: node linkType: hard -"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3": - version: 3.1.4 - resolution: "es6-symbol@npm:3.1.4" - dependencies: - d: ^1.0.2 - ext: ^1.7.0 - checksum: 52125ec4b5d1b6b93b8d3d42830bb19f8da21080ffcf45253b614bc6ff3e31349be202fb745d4d1af6778cdf5e38fea30e0c7e7dc37e2aecd44acc43502055f9 - languageName: node - linkType: hard - "escalade@npm:^3.1.1": version: 3.1.2 - resolution: "escalade@npm:3.1.2" - checksum: 1ec0977aa2772075493002bdbd549d595ff6e9393b1cb0d7d6fcaf78c750da0c158f180938365486f75cb69fba20294351caddfce1b46552a7b6c3cde52eaa02 - languageName: node - linkType: hard - -"escape-html@npm:~1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 + resolution: "escalade@npm:3.1.2" + checksum: 1ec0977aa2772075493002bdbd549d595ff6e9393b1cb0d7d6fcaf78c750da0c158f180938365486f75cb69fba20294351caddfce1b46552a7b6c3cde52eaa02 languageName: node linkType: hard @@ -6813,7 +4891,7 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": +"escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 @@ -7201,18 +5279,6 @@ __metadata: languageName: node linkType: hard -"esniff@npm:^2.0.1": - version: 2.0.1 - resolution: "esniff@npm:2.0.1" - dependencies: - d: ^1.0.1 - es5-ext: ^0.10.62 - event-emitter: ^0.3.5 - type: ^2.7.2 - checksum: d814c0e5c39bce9925b2e65b6d8767af72c9b54f35a65f9f3d6e8c606dce9aebe35a9599d30f15b0807743f88689f445163cfb577a425de4fb8c3c5bc16710cc - languageName: node - linkType: hard - "espree@npm:^6.1.2": version: 6.2.1 resolution: "espree@npm:6.2.1" @@ -7301,186 +5367,6 @@ __metadata: languageName: node linkType: hard -"etag@npm:~1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff - languageName: node - linkType: hard - -"eth-block-tracker@npm:^3.0.0": - version: 3.0.1 - resolution: "eth-block-tracker@npm:3.0.1" - dependencies: - eth-query: ^2.1.0 - ethereumjs-tx: ^1.3.3 - ethereumjs-util: ^5.1.3 - ethjs-util: ^0.1.3 - json-rpc-engine: ^3.6.0 - pify: ^2.3.0 - tape: ^4.6.3 - checksum: b68dda7a60e2c15fa7097f31277ebfce08852de83229c2c65879a5482db28610bc85248cfe6578971ad2357552d5ce6124fb0c2a29d18fd30c70f092beeda3b8 - languageName: node - linkType: hard - -"eth-ens-namehash@npm:2.0.8, eth-ens-namehash@npm:^2.0.8": - version: 2.0.8 - resolution: "eth-ens-namehash@npm:2.0.8" - dependencies: - idna-uts46-hx: ^2.3.1 - js-sha3: ^0.5.7 - checksum: 40ce4aeedaa4e7eb4485c8d8857457ecc46a4652396981d21b7e3a5f922d5beff63c71cb4b283c935293e530eba50b329d9248be3c433949c6bc40c850c202a3 - languageName: node - linkType: hard - -"eth-gas-reporter@npm:^0.2.25": - version: 0.2.27 - resolution: "eth-gas-reporter@npm:0.2.27" - dependencies: - "@solidity-parser/parser": ^0.14.0 - axios: ^1.5.1 - cli-table3: ^0.5.0 - colors: 1.4.0 - ethereum-cryptography: ^1.0.3 - ethers: ^5.7.2 - fs-readdir-recursive: ^1.1.0 - lodash: ^4.17.14 - markdown-table: ^1.1.3 - mocha: ^10.2.0 - req-cwd: ^2.0.0 - sha1: ^1.1.1 - sync-request: ^6.0.0 - peerDependencies: - "@codechecks/client": ^0.1.0 - peerDependenciesMeta: - "@codechecks/client": - optional: true - checksum: 9a26a4936693de6dbe633a9e6f9d69eb93c9d45c61ecbc20702a72f15ade424785e29ae8e62ea3a2afc49ea22a4777a71914dc8da1b8587e9d47d085a3246784 - languageName: node - linkType: hard - -"eth-json-rpc-infura@npm:^3.1.0": - version: 3.2.1 - resolution: "eth-json-rpc-infura@npm:3.2.1" - dependencies: - cross-fetch: ^2.1.1 - eth-json-rpc-middleware: ^1.5.0 - json-rpc-engine: ^3.4.0 - json-rpc-error: ^2.0.0 - checksum: 393e825986c0eedb9a1bb771b84e5b7c4037d8f870ab92cdba9dbaa52b5c7d5755ed02fd80d2a07b5db7a3af2c0b30d37756eb39cd7d2ae39173c6c2ea138e7d - languageName: node - linkType: hard - -"eth-json-rpc-middleware@npm:^1.5.0": - version: 1.6.0 - resolution: "eth-json-rpc-middleware@npm:1.6.0" - dependencies: - async: ^2.5.0 - eth-query: ^2.1.2 - eth-tx-summary: ^3.1.2 - ethereumjs-block: ^1.6.0 - ethereumjs-tx: ^1.3.3 - ethereumjs-util: ^5.1.2 - ethereumjs-vm: ^2.1.0 - fetch-ponyfill: ^4.0.0 - json-rpc-engine: ^3.6.0 - json-rpc-error: ^2.0.0 - json-stable-stringify: ^1.0.1 - promise-to-callback: ^1.0.0 - tape: ^4.6.3 - checksum: 0f6c146bdb277b3be9eef68f7424e1709a57f58330a3ae076153313be60f5026a5eee0de16d1ee6e41515e76cb1d38ef590948dd55d4b3ab1b3659af61337922 - languageName: node - linkType: hard - -"eth-lib@npm:0.2.8": - version: 0.2.8 - resolution: "eth-lib@npm:0.2.8" - dependencies: - bn.js: ^4.11.6 - elliptic: ^6.4.0 - xhr-request-promise: ^0.1.2 - checksum: be7efb0b08a78e20d12d2892363ecbbc557a367573ac82fc26a549a77a1b13c7747e6eadbb88026634828fcf9278884b555035787b575b1cab5e6958faad0fad - languageName: node - linkType: hard - -"eth-lib@npm:^0.1.26": - version: 0.1.29 - resolution: "eth-lib@npm:0.1.29" - dependencies: - bn.js: ^4.11.6 - elliptic: ^6.4.0 - nano-json-stream-parser: ^0.1.2 - servify: ^0.1.12 - ws: ^3.0.0 - xhr-request-promise: ^0.1.2 - checksum: d1494fc0af372d46d1c9e7506cfbfa81b9073d98081cf4cbe518932f88bee40cf46a764590f1f8aba03d4a534fa2b1cd794fa2a4f235f656d82b8ab185b5cb9d - languageName: node - linkType: hard - -"eth-query@npm:^2.0.2, eth-query@npm:^2.1.0, eth-query@npm:^2.1.2": - version: 2.1.2 - resolution: "eth-query@npm:2.1.2" - dependencies: - json-rpc-random-id: ^1.0.0 - xtend: ^4.0.1 - checksum: 83daa0e28452c54722aec78cd24d036bad5b6e7c08035d98e10d4bea11f71662f12cab63ebd8a848d4df46ad316503d54ecccb41c9244d2ea8b29364b0a20201 - languageName: node - linkType: hard - -"eth-sig-util@npm:3.0.0": - version: 3.0.0 - resolution: "eth-sig-util@npm:3.0.0" - dependencies: - buffer: ^5.2.1 - elliptic: ^6.4.0 - ethereumjs-abi: 0.6.5 - ethereumjs-util: ^5.1.1 - tweetnacl: ^1.0.0 - tweetnacl-util: ^0.15.0 - checksum: fbe44efb7909737b070e1e1d8c7096da3bdbd1356de242fc3458849e042e39c83a4e2dd1cbce0dc21ff3e5eca1843981751428bc160dcf3a6fcca2f1e8161be4 - languageName: node - linkType: hard - -"eth-sig-util@npm:^1.4.2": - version: 1.4.2 - resolution: "eth-sig-util@npm:1.4.2" - dependencies: - ethereumjs-abi: "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util: ^5.1.1 - checksum: 578f5c571c1bb0a86dc1bd4a5b56b8073b37823496d7afa74d772cf91ae6860f91bafcbee931be39a3d13f0c195df9f026a27fce350605ad5d15901a5a4ea94a - languageName: node - linkType: hard - -"eth-tx-summary@npm:^3.1.2": - version: 3.2.4 - resolution: "eth-tx-summary@npm:3.2.4" - dependencies: - async: ^2.1.2 - clone: ^2.0.0 - concat-stream: ^1.5.1 - end-of-stream: ^1.1.0 - eth-query: ^2.0.2 - ethereumjs-block: ^1.4.1 - ethereumjs-tx: ^1.1.1 - ethereumjs-util: ^5.0.1 - ethereumjs-vm: ^2.6.0 - through2: ^2.0.3 - checksum: 7df8b91bc2bd3f6941e2a5b3230cad5c5523ca3750190cd06af07983feba1bb4af893f226f01072958b00aa626869846894bcb1bfaa451d9c8f7f5b8cdf5ce0a - languageName: node - linkType: hard - -"ethashjs@npm:~0.0.7": - version: 0.0.8 - resolution: "ethashjs@npm:0.0.8" - dependencies: - async: ^2.1.2 - buffer-xor: ^2.0.1 - ethereumjs-util: ^7.0.2 - miller-rabin: ^4.0.0 - checksum: d9b6b47d32cbe017848ce5d8aec86eb6416300c6f52a68029bf6fc8fcf5429a45c14f2033d514435acd02047af16f6f804056e81587b30ed677039ac678b15f8 - languageName: node - linkType: hard - "ethereum-bloom-filters@npm:^1.0.6": version: 1.1.0 resolution: "ethereum-bloom-filters@npm:1.1.0" @@ -7490,20 +5376,6 @@ __metadata: languageName: node linkType: hard -"ethereum-common@npm:0.2.0": - version: 0.2.0 - resolution: "ethereum-common@npm:0.2.0" - checksum: 5e80af27482530ac700676502cd4c02a7248c064999d01dced302f5f40a180c86f57caaab347dbd12482c2869539d321c8c0039db9e3dfb1411e6ad3d57b2547 - languageName: node - linkType: hard - -"ethereum-common@npm:^0.0.18": - version: 0.0.18 - resolution: "ethereum-common@npm:0.0.18" - checksum: 2244126199604abc17508ca249c6f8a66a2ed02e9c97115f234e311f42e2d67aedff08128569fa3dfb8a2d09e1c194eace39a1ce61bfeb2338b6d3f2ac324ee8 - languageName: node - linkType: hard - "ethereum-cryptography@npm:0.1.3, ethereum-cryptography@npm:^0.1.3": version: 0.1.3 resolution: "ethereum-cryptography@npm:0.1.3" @@ -7539,7 +5411,7 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.1.3": +"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.1.3, ethereum-cryptography@npm:^2.2.1": version: 2.2.1 resolution: "ethereum-cryptography@npm:2.2.1" dependencies: @@ -7551,21 +5423,6 @@ __metadata: languageName: node linkType: hard -"ethereum-waffle@npm:^3.4.4": - version: 3.4.4 - resolution: "ethereum-waffle@npm:3.4.4" - dependencies: - "@ethereum-waffle/chai": ^3.4.4 - "@ethereum-waffle/compiler": ^3.4.4 - "@ethereum-waffle/mock-contract": ^3.4.4 - "@ethereum-waffle/provider": ^3.4.4 - ethers: ^5.0.1 - bin: - waffle: bin/waffle - checksum: 5a181b52f66f1b3c89ed1b68ef44cbd9acd4d743262de9edbe1fd57b0925576dd62c3436b1e65434d5ac03ab16da0df283972cd9aae726de0b8b9cdd7876b917 - languageName: node - linkType: hard - "ethereum-waffle@npm:latest": version: 4.0.10 resolution: "ethereum-waffle@npm:4.0.10" @@ -7584,26 +5441,6 @@ __metadata: languageName: node linkType: hard -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version: 0.6.8 - resolution: "ethereumjs-abi@https://github.com/ethereumjs/ethereumjs-abi.git#commit=ee3994657fa7a427238e6ba92a84d0b529bbcde0" - dependencies: - bn.js: ^4.11.8 - ethereumjs-util: ^6.0.0 - checksum: ae074be0bb012857ab5d3ae644d1163b908a48dd724b7d2567cfde309dc72222d460438f2411936a70dc949dc604ce1ef7118f7273bd525815579143c907e336 - languageName: node - linkType: hard - -"ethereumjs-abi@npm:0.6.5": - version: 0.6.5 - resolution: "ethereumjs-abi@npm:0.6.5" - dependencies: - bn.js: ^4.10.0 - ethereumjs-util: ^4.3.0 - checksum: 3abdc79dc60614d30b1cefb5e6bfbdab3ca8252b4e742330544103f86d6e49a55921d9b8822a0a47fee3efd9dd2493ec93448b1869d82479a4c71a44001e8337 - languageName: node - linkType: hard - "ethereumjs-abi@npm:0.6.8, ethereumjs-abi@npm:^0.6.8": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" @@ -7614,107 +5451,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-account@npm:3.0.0, ethereumjs-account@npm:^3.0.0": - version: 3.0.0 - resolution: "ethereumjs-account@npm:3.0.0" - dependencies: - ethereumjs-util: ^6.0.0 - rlp: ^2.2.1 - safe-buffer: ^5.1.1 - checksum: 64dbe026d29aca12c79596cf4085fb27e209988f11b7d5bf3a1f2aadaaa517d90d722680c8b525144c26a2d9cd8494aa26ac088fa80b358cc3e28024f7ddbe81 - languageName: node - linkType: hard - -"ethereumjs-account@npm:^2.0.3": - version: 2.0.5 - resolution: "ethereumjs-account@npm:2.0.5" - dependencies: - ethereumjs-util: ^5.0.0 - rlp: ^2.0.0 - safe-buffer: ^5.1.1 - checksum: 2e4546b8b0213168eebd3a5296da904b6f55470e39b4c742d252748927d2b268f8d6374b0178c1d5b7188646f97dae74a7ac1c7485fe96ea557c152b52223f18 - languageName: node - linkType: hard - -"ethereumjs-block@npm:2.2.2, ethereumjs-block@npm:^2.2.2, ethereumjs-block@npm:~2.2.0, ethereumjs-block@npm:~2.2.2": - version: 2.2.2 - resolution: "ethereumjs-block@npm:2.2.2" - dependencies: - async: ^2.0.1 - ethereumjs-common: ^1.5.0 - ethereumjs-tx: ^2.1.1 - ethereumjs-util: ^5.0.0 - merkle-patricia-tree: ^2.1.2 - checksum: 91f7f60820394e072c9a115da2871a096414644109d2449d4a79b30be67b0080bc848dfa7e2ae7b2ab255de3be4f6736c6cb2b418c29eada794d018cc384e189 - languageName: node - linkType: hard - -"ethereumjs-block@npm:^1.2.2, ethereumjs-block@npm:^1.4.1, ethereumjs-block@npm:^1.6.0": - version: 1.7.1 - resolution: "ethereumjs-block@npm:1.7.1" - dependencies: - async: ^2.0.1 - ethereum-common: 0.2.0 - ethereumjs-tx: ^1.2.2 - ethereumjs-util: ^5.0.0 - merkle-patricia-tree: ^2.1.2 - checksum: 9967c3674af77ea8475a3c023fa160ef6b614450ec50fa32ac083909ead22d3d1c3148f9407b6593d3ccfbe0c51f889c26aa1c15b17026fc2d35cbc542822af8 - languageName: node - linkType: hard - -"ethereumjs-blockchain@npm:^4.0.3": - version: 4.0.4 - resolution: "ethereumjs-blockchain@npm:4.0.4" - dependencies: - async: ^2.6.1 - ethashjs: ~0.0.7 - ethereumjs-block: ~2.2.2 - ethereumjs-common: ^1.5.0 - ethereumjs-util: ^6.1.0 - flow-stoplight: ^1.0.0 - level-mem: ^3.0.1 - lru-cache: ^5.1.1 - rlp: ^2.2.2 - semaphore: ^1.1.0 - checksum: efa04b2e2d02ce9c524f246f862b1ca779bbfd9f795cc7a9e471f0d96229de5188f1f6b17e54948f640100116b646ed03242494c23cd66f0f7e8384a4f217ba4 - languageName: node - linkType: hard - -"ethereumjs-common@npm:1.5.0": - version: 1.5.0 - resolution: "ethereumjs-common@npm:1.5.0" - checksum: a30474986a88b8f3ee53f9fb34027528f12d1bc7ecee8b80aa8060a09ccde3b2af4dd24c928287018003e4e206cd4f6311cdd508442d1452d02ec3d8e7a0601e - languageName: node - linkType: hard - -"ethereumjs-common@npm:^1.1.0, ethereumjs-common@npm:^1.3.2, ethereumjs-common@npm:^1.5.0": - version: 1.5.2 - resolution: "ethereumjs-common@npm:1.5.2" - checksum: 3fc64faced268e0c61da50c5db76d18cfd44325d5706792f32ac8c85c0e800d52db284f042c3bd0623daf59b946176ef7dbea476d1b0252492137fa4549a3349 - languageName: node - linkType: hard - -"ethereumjs-tx@npm:2.1.2, ethereumjs-tx@npm:^2.1.1, ethereumjs-tx@npm:^2.1.2": - version: 2.1.2 - resolution: "ethereumjs-tx@npm:2.1.2" - dependencies: - ethereumjs-common: ^1.5.0 - ethereumjs-util: ^6.0.0 - checksum: a5b607b4e125ed696d76a9e4db8a95e03a967323c66694912d799619b16fa43985336924221f9e7582dc1b09ff88a62116bf2290ee14d952bf7e6715e5728525 - languageName: node - linkType: hard - -"ethereumjs-tx@npm:^1.1.1, ethereumjs-tx@npm:^1.2.0, ethereumjs-tx@npm:^1.2.2, ethereumjs-tx@npm:^1.3.3": - version: 1.3.7 - resolution: "ethereumjs-tx@npm:1.3.7" - dependencies: - ethereum-common: ^0.0.18 - ethereumjs-util: ^5.0.0 - checksum: fe2323fe7db7f5dda85715dc67c31dd1f2925bf5a88e393ba939dbe699b73df008f1332f711b1aa37e943193acf3b6976202a33f2fab1f7675b6d2dd70f424d4 - languageName: node - linkType: hard - -"ethereumjs-util@npm:6.2.1, ethereumjs-util@npm:^6.0.0, ethereumjs-util@npm:^6.1.0, ethereumjs-util@npm:^6.2.0, ethereumjs-util@npm:^6.2.1": +"ethereumjs-util@npm:6.2.1, ethereumjs-util@npm:^6.0.0, ethereumjs-util@npm:^6.2.1": version: 6.2.1 resolution: "ethereumjs-util@npm:6.2.1" dependencies: @@ -7742,35 +5479,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-util@npm:^4.3.0": - version: 4.5.1 - resolution: "ethereumjs-util@npm:4.5.1" - dependencies: - bn.js: ^4.8.0 - create-hash: ^1.1.2 - elliptic: ^6.5.2 - ethereum-cryptography: ^0.1.3 - rlp: ^2.0.0 - checksum: ee91fbd29634d40cad9adf90f202158324c089bbc10b405d2ef139f4542090e6f76a616d16c601b52d6b5c5d59ddb6c8387cf60cc732884e732dad9a62b8a539 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^5.0.0, ethereumjs-util@npm:^5.0.1, ethereumjs-util@npm:^5.1.1, ethereumjs-util@npm:^5.1.2, ethereumjs-util@npm:^5.1.3, ethereumjs-util@npm:^5.1.5, ethereumjs-util@npm:^5.2.0": - version: 5.2.1 - resolution: "ethereumjs-util@npm:5.2.1" - dependencies: - bn.js: ^4.11.0 - create-hash: ^1.1.2 - elliptic: ^6.5.2 - ethereum-cryptography: ^0.1.3 - ethjs-util: ^0.1.3 - rlp: ^2.0.0 - safe-buffer: ^5.1.1 - checksum: 20db6c639d92b35739fd5f7a71e64a92e85442ea0d176b59b5cd5828265b6cf42bd4868cf81a9b20a83738db1ffa7a2f778f1d850d663627a1a5209f7904b44f - languageName: node - linkType: hard - -"ethereumjs-util@npm:^7.0.2, ethereumjs-util@npm:^7.0.3, ethereumjs-util@npm:^7.1.1, ethereumjs-util@npm:^7.1.3, ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": +"ethereumjs-util@npm:^7.0.3, ethereumjs-util@npm:^7.1.1, ethereumjs-util@npm:^7.1.3, ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": version: 7.1.5 resolution: "ethereumjs-util@npm:7.1.5" dependencies: @@ -7783,66 +5492,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-vm@npm:4.2.0": - version: 4.2.0 - resolution: "ethereumjs-vm@npm:4.2.0" - dependencies: - async: ^2.1.2 - async-eventemitter: ^0.2.2 - core-js-pure: ^3.0.1 - ethereumjs-account: ^3.0.0 - ethereumjs-block: ^2.2.2 - ethereumjs-blockchain: ^4.0.3 - ethereumjs-common: ^1.5.0 - ethereumjs-tx: ^2.1.2 - ethereumjs-util: ^6.2.0 - fake-merkle-patricia-tree: ^1.0.1 - functional-red-black-tree: ^1.0.1 - merkle-patricia-tree: ^2.3.2 - rustbn.js: ~0.2.0 - safe-buffer: ^5.1.1 - util.promisify: ^1.0.0 - checksum: ca73c406d55baefacafbdd8cefce80740098e5834096042e93285dc386ee670b4fed2f7846b78e3078fdf41231d04b3f1c40e435e639d072e0529ccb560b797b - languageName: node - linkType: hard - -"ethereumjs-vm@npm:^2.1.0, ethereumjs-vm@npm:^2.3.4, ethereumjs-vm@npm:^2.6.0": - version: 2.6.0 - resolution: "ethereumjs-vm@npm:2.6.0" - dependencies: - async: ^2.1.2 - async-eventemitter: ^0.2.2 - ethereumjs-account: ^2.0.3 - ethereumjs-block: ~2.2.0 - ethereumjs-common: ^1.1.0 - ethereumjs-util: ^6.0.0 - fake-merkle-patricia-tree: ^1.0.1 - functional-red-black-tree: ^1.0.1 - merkle-patricia-tree: ^2.3.2 - rustbn.js: ~0.2.0 - safe-buffer: ^5.1.1 - checksum: 3b3098b2ac3d5335797e4d73fceb76d1b776e453abb5fa4d1cd94f6391f493e95e3c89a8ee602558bc2a3b36b89977e66473de73faa87c8540b1954aa7b8c3fd - languageName: node - linkType: hard - -"ethereumjs-wallet@npm:0.6.5": - version: 0.6.5 - resolution: "ethereumjs-wallet@npm:0.6.5" - dependencies: - aes-js: ^3.1.1 - bs58check: ^2.1.2 - ethereum-cryptography: ^0.1.3 - ethereumjs-util: ^6.0.0 - randombytes: ^2.0.6 - safe-buffer: ^5.1.2 - scryptsy: ^1.2.1 - utf8: ^3.0.0 - uuid: ^3.3.2 - checksum: 54a9cc8beb8ea55e9be9b024b6ed09349423145fd8c49b8662d60d9258039330163c830fec055f92becc71ea54b430d2ef29f6bd73fa49d93ea854af01d13e58 - languageName: node - linkType: hard - -"ethers-v5@npm:ethers@^5.7.0, ethers@npm:^5.0.1, ethers@npm:^5.0.2, ethers@npm:^5.5.2, ethers@npm:^5.6.9, ethers@npm:^5.7.2": +"ethers-v5@npm:ethers@^5.7.0": version: 5.7.2 resolution: "ethers@npm:5.7.2" dependencies: @@ -7905,7 +5555,7 @@ __metadata: languageName: node linkType: hard -"ethjs-util@npm:0.1.6, ethjs-util@npm:^0.1.3, ethjs-util@npm:^0.1.6": +"ethjs-util@npm:0.1.6, ethjs-util@npm:^0.1.6": version: 0.1.6 resolution: "ethjs-util@npm:0.1.6" dependencies: @@ -7915,16 +5565,6 @@ __metadata: languageName: node linkType: hard -"event-emitter@npm:^0.3.5": - version: 0.3.5 - resolution: "event-emitter@npm:0.3.5" - dependencies: - d: 1 - es5-ext: ~0.10.14 - checksum: 27c1399557d9cd7e0aa0b366c37c38a4c17293e3a10258e8b692a847dd5ba9fb90429c3a5a1eeff96f31f6fa03ccbd31d8ad15e00540b22b22f01557be706030 - languageName: node - linkType: hard - "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1" @@ -7932,21 +5572,7 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:4.0.4": - version: 4.0.4 - resolution: "eventemitter3@npm:4.0.4" - checksum: 7afb1cd851d19898bc99cc55ca894fe18cb1f8a07b0758652830a09bd6f36082879a25345be6219b81d74764140688b1a8fa75bcd1073d96b9a6661e444bc2ea - languageName: node - linkType: hard - -"events@npm:^3.0.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780 - languageName: node - linkType: hard - -"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": +"evp_bytestokey@npm:^1.0.3": version: 1.0.3 resolution: "evp_bytestokey@npm:1.0.3" dependencies: @@ -7990,21 +5616,6 @@ __metadata: languageName: node linkType: hard -"expand-brackets@npm:^2.1.4": - version: 2.1.4 - resolution: "expand-brackets@npm:2.1.4" - dependencies: - debug: ^2.3.3 - define-property: ^0.2.5 - extend-shallow: ^2.0.1 - posix-character-classes: ^0.1.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: 1781d422e7edfa20009e2abda673cadb040a6037f0bd30fcd7357304f4f0c284afd420d7622722ca4a016f39b6d091841ab57b401c1f7e2e5131ac65b9f14fa1 - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -8012,73 +5623,6 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.14.0": - version: 4.19.2 - resolution: "express@npm:4.19.2" - dependencies: - accepts: ~1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.2 - content-disposition: 0.5.4 - content-type: ~1.0.4 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - etag: ~1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: ~1.1.2 - on-finished: 2.4.1 - parseurl: ~1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: ~2.0.7 - qs: 6.11.0 - range-parser: ~1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: ~1.6.18 - utils-merge: 1.0.1 - vary: ~1.1.2 - checksum: 212dbd6c2c222a96a61bc927639c95970a53b06257080bb9e2838adb3bffdb966856551fdad1ab5dd654a217c35db94f987d0aa88d48fb04d306340f5f34dca5 - languageName: node - linkType: hard - -"ext@npm:^1.7.0": - version: 1.7.0 - resolution: "ext@npm:1.7.0" - dependencies: - type: ^2.7.2 - checksum: ef481f9ef45434d8c867cfd09d0393b60945b7c8a1798bedc4514cb35aac342ccb8d8ecb66a513e6a2b4ec1e294a338e3124c49b29736f8e7c735721af352c31 - languageName: node - linkType: hard - -"extend-shallow@npm:^2.0.1": - version: 2.0.1 - resolution: "extend-shallow@npm:2.0.1" - dependencies: - is-extendable: ^0.1.0 - checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 - languageName: node - linkType: hard - -"extend-shallow@npm:^3.0.0, extend-shallow@npm:^3.0.2": - version: 3.0.2 - resolution: "extend-shallow@npm:3.0.2" - dependencies: - assign-symbols: ^1.0.0 - is-extendable: ^1.0.1 - checksum: a920b0cd5838a9995ace31dfd11ab5e79bf6e295aa566910ce53dff19f4b1c0fda2ef21f26b28586c7a2450ca2b42d97bd8c0f5cec9351a819222bf861e02461 - languageName: node - linkType: hard - "extend@npm:~3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -8097,22 +5641,6 @@ __metadata: languageName: node linkType: hard -"extglob@npm:^2.0.4": - version: 2.0.4 - resolution: "extglob@npm:2.0.4" - dependencies: - array-unique: ^0.3.2 - define-property: ^1.0.0 - expand-brackets: ^2.1.4 - extend-shallow: ^2.0.1 - fragment-cache: ^0.2.1 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: a41531b8934735b684cef5e8c5a01d0f298d7d384500ceca38793a9ce098125aab04ee73e2d75d5b2901bc5dddd2b64e1b5e3bf19139ea48bac52af4a92f1d00 - languageName: node - linkType: hard - "extsprintf@npm:1.3.0": version: 1.3.0 resolution: "extsprintf@npm:1.3.0" @@ -8134,15 +5662,6 @@ __metadata: languageName: node linkType: hard -"fake-merkle-patricia-tree@npm:^1.0.1": - version: 1.0.1 - resolution: "fake-merkle-patricia-tree@npm:1.0.1" - dependencies: - checkpoint-store: ^1.1.0 - checksum: 8f9fe05bb5beabb31e4fbb8d2cfe83cfb36fd9f6ba78193dea8fab7a679470d45bb04c6f052d4f79da03e81129c5b5bed528902430184e1e11b4959f397019ac - languageName: node - linkType: hard - "fast-base64-decode@npm:^1.0.0": version: 1.0.0 resolution: "fast-base64-decode@npm:1.0.0" @@ -8207,12 +5726,15 @@ __metadata: languageName: node linkType: hard -"fetch-ponyfill@npm:^4.0.0": - version: 4.1.0 - resolution: "fetch-ponyfill@npm:4.1.0" - dependencies: - node-fetch: ~1.7.1 - checksum: 00c85b661a8314e18cb314640b69d3b6e9635517d54290c8f366ddcb21b506ac8fa5d92f899c0fe21bc2163238130be2cf73ffd9d5a8a41a9866a55c52f57f16 +"fdir@npm:^6.4.2": + version: 6.4.2 + resolution: "fdir@npm:6.4.2" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 517ad31c495f1c0778238eef574a7818788efaaf2ce1969ffa18c70793e2951a9763dfa2e6720b8fcef615e602a3cbb47f9b8aea9da0b02147579ab36043f22f languageName: node linkType: hard @@ -8239,19 +5761,7 @@ __metadata: resolution: "file-entry-cache@npm:6.0.1" dependencies: flat-cache: ^3.0.4 - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 - languageName: node - linkType: hard - -"fill-range@npm:^4.0.0": - version: 4.0.0 - resolution: "fill-range@npm:4.0.0" - dependencies: - extend-shallow: ^2.0.1 - is-number: ^3.0.0 - repeat-string: ^1.6.1 - to-regex-range: ^2.1.0 - checksum: dbb5102467786ab42bc7a3ec7380ae5d6bfd1b5177b2216de89e4a541193f8ba599a6db84651bd2c58c8921db41b8cc3d699ea83b477342d3ce404020f73c298 + checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 languageName: node linkType: hard @@ -8264,31 +5774,6 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" - dependencies: - debug: 2.6.9 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - on-finished: 2.4.1 - parseurl: ~1.3.3 - statuses: 2.0.1 - unpipe: ~1.0.0 - checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 - languageName: node - linkType: hard - -"find-replace@npm:^1.0.3": - version: 1.0.3 - resolution: "find-replace@npm:1.0.3" - dependencies: - array-back: ^1.0.4 - test-value: ^2.1.0 - checksum: fd95f44e59bd54ea1c0169480952b339a4642cd62d81236fef7f87146d3bc00a042b17d81f896712e8542e01fe5c84e82ac37b6b77b4e3422abbcf7c13bbacfd - languageName: node - linkType: hard - "find-replace@npm:^3.0.0": version: 3.0.0 resolution: "find-replace@npm:3.0.0" @@ -8308,25 +5793,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^1.0.0": - version: 1.1.2 - resolution: "find-up@npm:1.1.2" - dependencies: - path-exists: ^2.0.0 - pinkie-promise: ^2.0.0 - checksum: a2cb9f4c9f06ee3a1e92ed71d5aed41ac8ae30aefa568132f6c556fac7678a5035126153b59eaec68da78ac409eef02503b2b059706bdbf232668d7245e3240a - languageName: node - linkType: hard - -"find-up@npm:^2.1.0": - version: 2.1.0 - resolution: "find-up@npm:2.1.0" - dependencies: - locate-path: ^2.0.0 - checksum: 43284fe4da09f89011f08e3c32cd38401e786b19226ea440b75386c1b12a4cb738c94969808d53a84f564ede22f732c8409e3cfc3f7fb5b5c32378ad0bbf28bd - languageName: node - linkType: hard - "find-up@npm:^3.0.0": version: 3.0.0 resolution: "find-up@npm:3.0.0" @@ -8336,25 +5802,6 @@ __metadata: languageName: node linkType: hard -"find-yarn-workspace-root@npm:^1.2.1": - version: 1.2.1 - resolution: "find-yarn-workspace-root@npm:1.2.1" - dependencies: - fs-extra: ^4.0.3 - micromatch: ^3.1.4 - checksum: a8f4565fb1ead6122acc0d324fa3257c20f7b0c91b7b266dab9eee7251fb5558fcff5b35dbfd301bfd1cbb91c1cdd1799b28ffa5b9a92efd8c7ded3663652bbe - languageName: node - linkType: hard - -"find-yarn-workspace-root@npm:^2.0.0": - version: 2.0.0 - resolution: "find-yarn-workspace-root@npm:2.0.0" - dependencies: - micromatch: ^4.0.2 - checksum: fa5ca8f9d08fe7a54ce7c0a5931ff9b7e36f9ee7b9475fb13752bcea80ec6b5f180fa5102d60b376d5526ce924ea3fc6b19301262efa0a5d248dd710f3644242 - languageName: node - linkType: hard - "flat-cache@npm:^2.0.1": version: 2.0.1 resolution: "flat-cache@npm:2.0.1" @@ -8400,13 +5847,6 @@ __metadata: languageName: node linkType: hard -"flow-stoplight@npm:^1.0.0": - version: 1.0.0 - resolution: "flow-stoplight@npm:1.0.0" - checksum: 2f1f34629e724afe7de7b6cb7b5f9ef1b37fa5a4b8a10e24b9c1043872777c41f4c7e09994ecfd5bc70138a04966c3153c4e15187a24771f5d5151a325a96a2e - languageName: node - linkType: hard - "follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.15.6": version: 1.15.6 resolution: "follow-redirects@npm:1.15.6" @@ -8417,7 +5857,7 @@ __metadata: languageName: node linkType: hard -"for-each@npm:^0.3.3, for-each@npm:~0.3.3": +"for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" dependencies: @@ -8426,13 +5866,6 @@ __metadata: languageName: node linkType: hard -"for-in@npm:^1.0.2": - version: 1.0.2 - resolution: "for-in@npm:1.0.2" - checksum: 09f4ae93ce785d253ac963d94c7f3432d89398bf25ac7a24ed034ca393bf74380bdeccc40e0f2d721a895e54211b07c8fad7132e8157827f6f7f059b70b4043d - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.2.1 resolution: "foreground-child@npm:3.2.1" @@ -8450,17 +5883,6 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^2.2.0": - version: 2.5.1 - resolution: "form-data@npm:2.5.1" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.6 - mime-types: ^2.1.12 - checksum: 5134ada56cc246b293a1ac7678dba6830000603a3979cf83ff7b2f21f2e3725202237cfb89e32bcb38a1d35727efbd3c3a22e65b42321e8ade8eec01ce755d08 - languageName: node - linkType: hard - "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -8483,13 +5905,6 @@ __metadata: languageName: node linkType: hard -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 - languageName: node - linkType: hard - "fp-ts@npm:1.19.3": version: 1.19.3 resolution: "fp-ts@npm:1.19.3" @@ -8504,22 +5919,6 @@ __metadata: languageName: node linkType: hard -"fragment-cache@npm:^0.2.1": - version: 0.2.1 - resolution: "fragment-cache@npm:0.2.1" - dependencies: - map-cache: ^0.2.2 - checksum: 1cbbd0b0116b67d5790175de0038a11df23c1cd2e8dcdbade58ebba5594c2d641dade6b4f126d82a7b4a6ffc2ea12e3d387dbb64ea2ae97cf02847d436f60fdc - languageName: node - linkType: hard - -"fresh@npm:0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" - checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 - languageName: node - linkType: hard - "fs-constants@npm:^1.0.0": version: 1.0.0 resolution: "fs-constants@npm:1.0.0" @@ -8527,30 +5926,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^0.30.0": - version: 0.30.0 - resolution: "fs-extra@npm:0.30.0" - dependencies: - graceful-fs: ^4.1.2 - jsonfile: ^2.1.0 - klaw: ^1.0.0 - path-is-absolute: ^1.0.0 - rimraf: ^2.2.8 - checksum: 6edfd65fc813baa27f1603778c0f5ec11f8c5006a20b920437813ee2023eba18aeec8bef1c89b2e6c84f9fc90fdc7c916f4a700466c8c69d22a35d018f2570f0 - languageName: node - linkType: hard - -"fs-extra@npm:^4.0.2, fs-extra@npm:^4.0.3": - version: 4.0.3 - resolution: "fs-extra@npm:4.0.3" - dependencies: - graceful-fs: ^4.1.2 - jsonfile: ^4.0.0 - universalify: ^0.1.0 - checksum: c5ae3c7043ad7187128e619c0371da01b58694c1ffa02c36fb3f5b459925d9c27c3cb1e095d9df0a34a85ca993d8b8ff6f6ecef868fd5ebb243548afa7fc0936 - languageName: node - linkType: hard - "fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" @@ -8595,15 +5970,6 @@ __metadata: languageName: node linkType: hard -"fs-minipass@npm:^1.2.7": - version: 1.2.7 - resolution: "fs-minipass@npm:1.2.7" - dependencies: - minipass: ^2.6.0 - checksum: 40fd46a2b5dcb74b3a580269f9a0c36f9098c2ebd22cef2e1a004f375b7b665c11f1507ec3f66ee6efab5664109f72d0a74ea19c3370842214c3da5168d6fdd7 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -8622,13 +5988,6 @@ __metadata: languageName: node linkType: hard -"fs-readdir-recursive@npm:^1.1.0": - version: 1.1.0 - resolution: "fs-readdir-recursive@npm:1.1.0" - checksum: 29d50f3d2128391c7fc9fd051c8b7ea45bcc8aa84daf31ef52b17218e20bfd2bd34d02382742801954cc8d1905832b68227f6b680a666ce525d8b6b75068ad1e - languageName: node - linkType: hard - "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" @@ -8688,7 +6047,7 @@ __metadata: languageName: node linkType: hard -"ganache-cli@npm:^6.12.2, ganache-cli@npm:latest": +"ganache-cli@npm:latest": version: 6.12.2 resolution: "ganache-cli@npm:6.12.2" dependencies: @@ -8701,49 +6060,6 @@ __metadata: languageName: node linkType: hard -"ganache-core@npm:^2.13.2": - version: 2.13.2 - resolution: "ganache-core@npm:2.13.2" - dependencies: - abstract-leveldown: 3.0.0 - async: 2.6.2 - bip39: 2.5.0 - cachedown: 1.0.0 - clone: 2.1.2 - debug: 3.2.6 - encoding-down: 5.0.4 - eth-sig-util: 3.0.0 - ethereumjs-abi: 0.6.8 - ethereumjs-account: 3.0.0 - ethereumjs-block: 2.2.2 - ethereumjs-common: 1.5.0 - ethereumjs-tx: 2.1.2 - ethereumjs-util: 6.2.1 - ethereumjs-vm: 4.2.0 - ethereumjs-wallet: 0.6.5 - heap: 0.2.6 - keccak: 3.0.1 - level-sublevel: 6.6.4 - levelup: 3.1.1 - lodash: 4.17.20 - lru-cache: 5.1.1 - merkle-patricia-tree: 3.0.0 - patch-package: 6.2.2 - seedrandom: 3.0.1 - source-map-support: 0.5.12 - tmp: 0.1.0 - web3: 1.2.11 - web3-provider-engine: 14.2.1 - websocket: 1.0.32 - dependenciesMeta: - ethereumjs-wallet: - optional: true - web3: - optional: true - checksum: 799b275abd09259c88a4e78c335e807d14cc12d3a1ceb9d7cdeef484cf5fab541847edf9cf209f448190199dbd0796393d308d50e6823565154c17dd0c3a4048 - languageName: node - linkType: hard - "ganache@npm:7.4.3": version: 7.4.3 resolution: "ganache@npm:7.4.3" @@ -8770,13 +6086,6 @@ __metadata: languageName: node linkType: hard -"get-caller-file@npm:^1.0.1": - version: 1.0.3 - resolution: "get-caller-file@npm:1.0.3" - checksum: 2b90a7f848896abcebcdc0acc627a435bcf05b9cd280599bc980ebfcdc222416c3df12c24c4845f69adc4346728e8966f70b758f9369f3534182791dfbc25c05 - languageName: node - linkType: hard - "get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -8811,13 +6120,6 @@ __metadata: languageName: node linkType: hard -"get-port@npm:^3.1.0": - version: 3.2.0 - resolution: "get-port@npm:3.2.0" - checksum: 31f530326569683ac4b7452eb7573c40e9dbe52aec14d80745c35475261e6389160da153d5b8ae911150b4ce99003472b30c69ba5be0cedeaa7865b95542d168 - languageName: node - linkType: hard - "get-stdin@npm:^6.0.0": version: 6.0.0 resolution: "get-stdin@npm:6.0.0" @@ -8825,7 +6127,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^4.0.0, get-stream@npm:^4.1.0": +"get-stream@npm:^4.0.0": version: 4.1.0 resolution: "get-stream@npm:4.1.0" dependencies: @@ -8834,7 +6136,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0": +"get-stream@npm:^5.0.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" dependencies: @@ -8854,13 +6156,6 @@ __metadata: languageName: node linkType: hard -"get-value@npm:^2.0.3, get-value@npm:^2.0.6": - version: 2.0.6 - resolution: "get-value@npm:2.0.6" - checksum: 5c3b99cb5398ea8016bf46ff17afc5d1d286874d2ad38ca5edb6e87d75c0965b0094cb9a9dddef2c59c23d250702323539a7fbdd870620db38c7e7d7ec87c1eb - languageName: node - linkType: hard - "getpass@npm:^0.1.1": version: 0.1.7 resolution: "getpass@npm:0.1.7" @@ -8914,20 +6209,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:7.2.0": - version: 7.2.0 - resolution: "glob@npm:7.2.0" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.0.4 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 78a8ea942331f08ed2e055cb5b9e40fe6f46f579d7fd3d694f3412fe5db23223d29b7fee1575440202e9a7ff9a72ab106a39fee39934c7bedafe5e5f8ae20134 - languageName: node - linkType: hard - "glob@npm:8.1.0, glob@npm:^8.0.3": version: 8.1.0 resolution: "glob@npm:8.1.0" @@ -8970,7 +6251,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.6, glob@npm:~7.2.3": +"glob@npm:^7.0.0, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -9004,16 +6285,6 @@ __metadata: languageName: node linkType: hard -"global@npm:~4.4.0": - version: 4.4.0 - resolution: "global@npm:4.4.0" - dependencies: - min-document: ^2.19.0 - process: ^0.11.10 - checksum: 9c057557c8f5a5bcfbeb9378ba4fe2255d04679452be504608dd5f13b54edf79f7be1db1031ea06a4ec6edd3b9f5f17d2d172fb47e6c69dae57fd84b7e72b77f - languageName: node - linkType: hard - "globals@npm:^12.1.0": version: 12.4.0 resolution: "globals@npm:12.4.0" @@ -9032,13 +6303,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^9.18.0": - version: 9.18.0 - resolution: "globals@npm:9.18.0" - checksum: e9c066aecfdc5ea6f727344a4246ecc243aaf66ede3bffee10ddc0c73351794c25e727dd046090dcecd821199a63b9de6af299a6e3ba292c8b22f0a80ea32073 - languageName: node - linkType: hard - "globalthis@npm:^1.0.3": version: 1.0.4 resolution: "globalthis@npm:1.0.4" @@ -9128,45 +6392,7 @@ __metadata: languageName: node linkType: hard -"got@npm:9.6.0": - version: 9.6.0 - resolution: "got@npm:9.6.0" - dependencies: - "@sindresorhus/is": ^0.14.0 - "@szmarczak/http-timer": ^1.1.2 - cacheable-request: ^6.0.0 - decompress-response: ^3.3.0 - duplexer3: ^0.1.4 - get-stream: ^4.1.0 - lowercase-keys: ^1.0.1 - mimic-response: ^1.0.1 - p-cancelable: ^1.0.0 - to-readable-stream: ^1.0.0 - url-parse-lax: ^3.0.0 - checksum: 941807bd9704bacf5eb401f0cc1212ffa1f67c6642f2d028fd75900471c221b1da2b8527f4553d2558f3faeda62ea1cf31665f8b002c6137f5de8732f07370b0 - languageName: node - linkType: hard - -"got@npm:^11.8.5": - version: 11.8.6 - resolution: "got@npm:11.8.6" - dependencies: - "@sindresorhus/is": ^4.0.0 - "@szmarczak/http-timer": ^4.0.5 - "@types/cacheable-request": ^6.0.1 - "@types/responselike": ^1.0.0 - cacheable-lookup: ^5.0.3 - cacheable-request: ^7.0.2 - decompress-response: ^6.0.0 - http2-wrapper: ^1.0.0-beta.5.2 - lowercase-keys: ^2.0.0 - p-cancelable: ^2.0.0 - responselike: ^2.0.0 - checksum: bbc783578a8d5030c8164ef7f57ce41b5ad7db2ed13371e1944bef157eeca5a7475530e07c0aaa71610d7085474d0d96222c9f4268d41db333a17e39b463f45d - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -9222,19 +6448,6 @@ __metadata: languageName: node linkType: hard -"hardhat-gas-reporter@npm:^1.0.9": - version: 1.0.10 - resolution: "hardhat-gas-reporter@npm:1.0.10" - dependencies: - array-uniq: 1.0.3 - eth-gas-reporter: ^0.2.25 - sha1: ^1.1.1 - peerDependencies: - hardhat: ^2.0.2 - checksum: caaec13ab3fcda47b8768257e4416b5fd0e8ef3aca5369aa8195419d3d4a948cc182075333651df44215cfc629d088f5ed9f762c8c14ae5a4b4a4f2613e583d0 - languageName: node - linkType: hard - "hardhat-gas-reporter@npm:latest": version: 2.2.0 resolution: "hardhat-gas-reporter@npm:2.2.0" @@ -9260,13 +6473,13 @@ __metadata: languageName: node linkType: hard -"hardhat@npm:^2.19.4": - version: 2.22.5 - resolution: "hardhat@npm:2.22.5" +"hardhat@npm:^2.22.18": + version: 2.22.18 + resolution: "hardhat@npm:2.22.18" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 - "@nomicfoundation/edr": ^0.4.0 + "@nomicfoundation/edr": ^0.7.0 "@nomicfoundation/ethereumjs-common": 4.0.4 "@nomicfoundation/ethereumjs-tx": 5.0.4 "@nomicfoundation/ethereumjs-util": 9.0.4 @@ -9278,31 +6491,32 @@ __metadata: aggregate-error: ^3.0.0 ansi-escapes: ^4.3.0 boxen: ^5.1.2 - chalk: ^2.4.2 - chokidar: ^3.4.0 + chokidar: ^4.0.0 ci-info: ^2.0.0 debug: ^4.1.1 enquirer: ^2.3.0 env-paths: ^2.2.0 ethereum-cryptography: ^1.0.3 ethereumjs-abi: ^0.6.8 - find-up: ^2.1.0 + find-up: ^5.0.0 fp-ts: 1.19.3 fs-extra: ^7.0.1 - glob: 7.2.0 immutable: ^4.0.0-rc.12 io-ts: 1.10.4 + json-stream-stringify: ^3.1.4 keccak: ^3.0.2 lodash: ^4.17.11 mnemonist: ^0.38.0 mocha: ^10.0.0 p-map: ^4.0.0 + picocolors: ^1.1.0 raw-body: ^2.4.1 resolve: 1.17.0 semver: ^6.3.0 - solc: 0.7.3 + solc: 0.8.26 source-map-support: ^0.5.13 stacktrace-parser: ^0.1.10 + tinyglobby: ^0.2.6 tsort: 0.0.1 undici: ^5.14.0 uuid: ^8.3.2 @@ -9317,20 +6531,17 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: 34ab9ae3820c26ea4c92db43aefb15668d0575787d214a408b3274d445a7626775f2966dca2cf82a8fa8d9f39ebfdc90f3fb7189409b9582e373ce5b66ec3855 + checksum: e350e80a96846a465e1ca0c92a30a83e5a04225b8def19c9703d049f4a05ac69ff12150f93bf647e3ce3f82e2264558c6a2cec1b8e8a8494b97ffbf241f54077 languageName: node linkType: hard -"hardhat@npm:^2.22.8": - version: 2.22.8 - resolution: "hardhat@npm:2.22.8" +"hardhat@npm:^2.23.0": + version: 2.23.0 + resolution: "hardhat@npm:2.23.0" dependencies: + "@ethereumjs/util": ^9.1.0 "@ethersproject/abi": ^5.1.2 - "@metamask/eth-sig-util": ^4.0.0 - "@nomicfoundation/edr": ^0.5.2 - "@nomicfoundation/ethereumjs-common": 4.0.4 - "@nomicfoundation/ethereumjs-tx": 5.0.4 - "@nomicfoundation/ethereumjs-util": 9.0.4 + "@nomicfoundation/edr": ^0.10.0 "@nomicfoundation/solidity-analyzer": ^0.1.0 "@sentry/node": ^5.18.1 "@types/bn.js": ^5.1.0 @@ -9339,31 +6550,32 @@ __metadata: aggregate-error: ^3.0.0 ansi-escapes: ^4.3.0 boxen: ^5.1.2 - chalk: ^2.4.2 - chokidar: ^3.4.0 + chokidar: ^4.0.0 ci-info: ^2.0.0 debug: ^4.1.1 enquirer: ^2.3.0 env-paths: ^2.2.0 ethereum-cryptography: ^1.0.3 - ethereumjs-abi: ^0.6.8 - find-up: ^2.1.0 + find-up: ^5.0.0 fp-ts: 1.19.3 fs-extra: ^7.0.1 - glob: 7.2.0 immutable: ^4.0.0-rc.12 io-ts: 1.10.4 + json-stream-stringify: ^3.1.4 keccak: ^3.0.2 lodash: ^4.17.11 + micro-eth-signer: ^0.14.0 mnemonist: ^0.38.0 mocha: ^10.0.0 p-map: ^4.0.0 + picocolors: ^1.1.0 raw-body: ^2.4.1 resolve: 1.17.0 semver: ^6.3.0 solc: 0.8.26 source-map-support: ^0.5.13 stacktrace-parser: ^0.1.10 + tinyglobby: ^0.2.6 tsort: 0.0.1 undici: ^5.14.0 uuid: ^8.3.2 @@ -9378,16 +6590,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: 3731b510540f800b3b931e3ad7db4510dbd35eff18f34382875778db43de2a5ce1c52596c392aa694324f66392e844fede85954ab3cdc08df3da10f2a810135f - languageName: node - linkType: hard - -"has-ansi@npm:^2.0.0": - version: 2.0.0 - resolution: "has-ansi@npm:2.0.0" - dependencies: - ansi-regex: ^2.0.0 - checksum: 1b51daa0214440db171ff359d0a2d17bc20061164c57e76234f614c91dbd2a79ddd68dfc8ee73629366f7be45a6df5f2ea9de83f52e1ca24433f2cc78c35d8ec + checksum: b2814cf5e996547b7a2c8f3b8bd116c34de94c3a1eca869aa5407622c8a93c1dda0b95064b004826df88594a91cbc149fba6f437af4743278790b7ffaf11acdb languageName: node linkType: hard @@ -9451,52 +6654,6 @@ __metadata: languageName: node linkType: hard -"has-value@npm:^0.3.1": - version: 0.3.1 - resolution: "has-value@npm:0.3.1" - dependencies: - get-value: ^2.0.3 - has-values: ^0.1.4 - isobject: ^2.0.0 - checksum: 29e2a1e6571dad83451b769c7ce032fce6009f65bccace07c2962d3ad4d5530b6743d8f3229e4ecf3ea8e905d23a752c5f7089100c1f3162039fa6dc3976558f - languageName: node - linkType: hard - -"has-value@npm:^1.0.0": - version: 1.0.0 - resolution: "has-value@npm:1.0.0" - dependencies: - get-value: ^2.0.6 - has-values: ^1.0.0 - isobject: ^3.0.0 - checksum: b9421d354e44f03d3272ac39fd49f804f19bc1e4fa3ceef7745df43d6b402053f828445c03226b21d7d934a21ac9cf4bc569396dc312f496ddff873197bbd847 - languageName: node - linkType: hard - -"has-values@npm:^0.1.4": - version: 0.1.4 - resolution: "has-values@npm:0.1.4" - checksum: ab1c4bcaf811ccd1856c11cfe90e62fca9e2b026ebe474233a3d282d8d67e3b59ed85b622c7673bac3db198cb98bd1da2b39300a2f98e453729b115350af49bc - languageName: node - linkType: hard - -"has-values@npm:^1.0.0": - version: 1.0.0 - resolution: "has-values@npm:1.0.0" - dependencies: - is-number: ^3.0.0 - kind-of: ^4.0.0 - checksum: 77e6693f732b5e4cf6c38dfe85fdcefad0fab011af74995c3e83863fabf5e3a836f406d83565816baa0bc0a523c9410db8b990fe977074d61aeb6d8f4fcffa11 - languageName: node - linkType: hard - -"has@npm:~1.0.3": - version: 1.0.4 - resolution: "has@npm:1.0.4" - checksum: 8a11ba062e0627c9578a1d08285401e39f1d071a9692ddf793199070edb5648b21c774dd733e2a181edd635bf6862731885f476f4ccf67c998d7a5ff7cef2550 - languageName: node - linkType: hard - "hash-base@npm:^3.0.0": version: 3.1.0 resolution: "hash-base@npm:3.1.0" @@ -9508,16 +6665,6 @@ __metadata: languageName: node linkType: hard -"hash-base@npm:~3.0": - version: 3.0.4 - resolution: "hash-base@npm:3.0.4" - dependencies: - inherits: ^2.0.1 - safe-buffer: ^5.0.1 - checksum: 878465a0dfcc33cce195c2804135352c590d6d10980adc91a9005fd377e77f2011256c2b7cfce472e3f2e92d561d1bf3228d2da06348a9017ce9a258b3b49764 - languageName: node - linkType: hard - "hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": version: 1.1.7 resolution: "hash.js@npm:1.1.7" @@ -9546,13 +6693,6 @@ __metadata: languageName: node linkType: hard -"heap@npm:0.2.6": - version: 0.2.6 - resolution: "heap@npm:0.2.6" - checksum: 1291b9b9efb5090d01c6d04a89c91ca6e0e0eb7f3694d8254f7a5effcc5ab9249bc3d16767b276645ffe86d9b2bbd82ed977f8988f55375e9f2a2c80647ebbdc - languageName: node - linkType: hard - "heap@npm:>= 0.2.0": version: 0.2.7 resolution: "heap@npm:0.2.7" @@ -9571,36 +6711,14 @@ __metadata: languageName: node linkType: hard -"home-or-tmp@npm:^2.0.0": - version: 2.0.0 - resolution: "home-or-tmp@npm:2.0.0" - dependencies: - os-homedir: ^1.0.0 - os-tmpdir: ^1.0.1 - checksum: b783c6ffd22f716d82f53e8c781cbe49bc9f4109a89ea86a27951e54c0bd335caf06bd828be2958cd9f4681986df1739558ae786abda6298cdd6d3edc2c362f1 - languageName: node - linkType: hard - -"hosted-git-info@npm:^2.1.4, hosted-git-info@npm:^2.6.0": +"hosted-git-info@npm:^2.6.0": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd languageName: node linkType: hard -"http-basic@npm:^8.1.1": - version: 8.1.3 - resolution: "http-basic@npm:8.1.3" - dependencies: - caseless: ^0.12.0 - concat-stream: ^1.6.2 - http-response-object: ^3.0.1 - parse-cache-control: ^1.0.1 - checksum: 7df5dc4d4b6eb8cc3beaa77f8e5c3074288ec3835abd83c85e5bb66d8a95a0ef97664d862caf5e225698cb795f78f9a5abd0d39404e5356ccd3e5e10c87936a5 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": +"http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 @@ -9620,13 +6738,6 @@ __metadata: languageName: node linkType: hard -"http-https@npm:^1.0.0": - version: 1.0.0 - resolution: "http-https@npm:1.0.0" - checksum: 82fc4d2e512c64b35680944d1ae13e68220acfa05b06329832e271fd199c5c7fcff1f53fc1f91a1cd65a737ee4de14004dd3ba9a73cce33da970940c6e6ca774 - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -9637,15 +6748,6 @@ __metadata: languageName: node linkType: hard -"http-response-object@npm:^3.0.1": - version: 3.0.2 - resolution: "http-response-object@npm:3.0.2" - dependencies: - "@types/node": ^10.0.3 - checksum: 6cbdcb4ce7b27c9158a131b772c903ed54add2ba831e29cc165e91c3969fa6f8105ddf924aac5b954b534ad15a1ae697b693331b2be5281ee24d79aae20c3264 - languageName: node - linkType: hard - "http-signature@npm:~1.2.0": version: 1.2.0 resolution: "http-signature@npm:1.2.0" @@ -9657,16 +6759,6 @@ __metadata: languageName: node linkType: hard -"http2-wrapper@npm:^1.0.0-beta.5.2": - version: 1.0.3 - resolution: "http2-wrapper@npm:1.0.3" - dependencies: - quick-lru: ^5.1.1 - resolve-alpn: ^1.0.0 - checksum: 74160b862ec699e3f859739101ff592d52ce1cb207b7950295bf7962e4aa1597ef709b4292c673bece9c9b300efad0559fc86c71b1409c7a1e02b7229456003e - languageName: node - linkType: hard - "https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -9712,15 +6804,6 @@ __metadata: languageName: node linkType: hard -"idna-uts46-hx@npm:^2.3.1": - version: 2.3.1 - resolution: "idna-uts46-hx@npm:2.3.1" - dependencies: - punycode: 2.1.0 - checksum: d434c3558d2bc1090eb90f978f995101f469cb26593414ac57aa082c9352e49972b332c6e4188b9b15538172ccfeae3121e5a19b96972a97e6aeb0676d86639c - languageName: node - linkType: hard - "ieee754@npm:^1.1.13, ieee754@npm:^1.1.4, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" @@ -9804,7 +6887,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3, inherits@npm:~2.0.4": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 @@ -9875,22 +6958,6 @@ __metadata: languageName: node linkType: hard -"invariant@npm:^2.2.2": - version: 2.2.4 - resolution: "invariant@npm:2.2.4" - dependencies: - loose-envify: ^1.0.0 - checksum: cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 - languageName: node - linkType: hard - -"invert-kv@npm:^1.0.0": - version: 1.0.0 - resolution: "invert-kv@npm:1.0.0" - checksum: aebeee31dda3b3d25ffd242e9a050926e7fe5df642d60953ab183aca1a7d1ffb39922eb2618affb0e850cf2923116f0da1345367759d88d097df5da1f1e1590e - languageName: node - linkType: hard - "invert-kv@npm:^2.0.0": version: 2.0.0 resolution: "invert-kv@npm:2.0.0" @@ -9924,13 +6991,6 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 - languageName: node - linkType: hard - "ipfs-core-types@npm:^0.9.0": version: 0.9.0 resolution: "ipfs-core-types@npm:0.9.0" @@ -10016,37 +7076,18 @@ __metadata: buffer: ^6.0.1 electron-fetch: ^1.7.2 err-code: ^3.0.1 - is-electron: ^2.2.0 - iso-url: ^1.1.5 - it-all: ^1.0.4 - it-glob: ^1.0.1 - it-to-stream: ^1.0.0 - merge-options: ^3.0.4 - nanoid: ^3.1.20 - native-fetch: ^3.0.0 - node-fetch: ^2.6.8 - react-native-fetch-api: ^3.0.0 - stream-to-it: ^0.2.2 - checksum: 08108e03ea7b90e0fa11b76a4e24bd29d7e027c603494b53c1cc37b367fb559eaeea7b0f10b2e83ee419d50cdcb4d8105febdf185cab75c7e55afd4c8ed51aba - languageName: node - linkType: hard - -"is-accessor-descriptor@npm:^1.0.1": - version: 1.0.1 - resolution: "is-accessor-descriptor@npm:1.0.1" - dependencies: - hasown: ^2.0.0 - checksum: 8db44c02230a5e9b9dec390a343178791f073d5d5556a400527d2fd67a72d93b226abab2bd4123305c268f5dc22831bfdbd38430441fda82ea9e0b95ddc6b267 - languageName: node - linkType: hard - -"is-arguments@npm:^1.1.1": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 + is-electron: ^2.2.0 + iso-url: ^1.1.5 + it-all: ^1.0.4 + it-glob: ^1.0.1 + it-to-stream: ^1.0.0 + merge-options: ^3.0.4 + nanoid: ^3.1.20 + native-fetch: ^3.0.0 + node-fetch: ^2.6.8 + react-native-fetch-api: ^3.0.0 + stream-to-it: ^0.2.2 + checksum: 08108e03ea7b90e0fa11b76a4e24bd29d7e027c603494b53c1cc37b367fb559eaeea7b0f10b2e83ee419d50cdcb4d8105febdf185cab75c7e55afd4c8ed51aba languageName: node linkType: hard @@ -10095,13 +7136,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.5": - version: 1.1.6 - resolution: "is-buffer@npm:1.1.6" - checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 - languageName: node - linkType: hard - "is-buffer@npm:^2.0.5": version: 2.0.5 resolution: "is-buffer@npm:2.0.5" @@ -10116,17 +7150,6 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^2.0.0": - version: 2.0.0 - resolution: "is-ci@npm:2.0.0" - dependencies: - ci-info: ^2.0.0 - bin: - is-ci: bin.js - checksum: 77b869057510f3efa439bbb36e9be429d53b3f51abd4776eeea79ab3b221337fe1753d1e50058a9e2c650d38246108beffb15ccfd443929d77748d8c0cc90144 - languageName: node - linkType: hard - "is-core-module@npm:^2.11.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1": version: 2.14.0 resolution: "is-core-module@npm:2.14.0" @@ -10136,15 +7159,6 @@ __metadata: languageName: node linkType: hard -"is-data-descriptor@npm:^1.0.1": - version: 1.0.1 - resolution: "is-data-descriptor@npm:1.0.1" - dependencies: - hasown: ^2.0.0 - checksum: fc6da5be5177149d554c5612cc382e9549418ed72f2d3ed5a3e6511b03dd119ae1b2258320ca94931df50b7e9ee012894eccd4ca45bbcadf0d5b27da6faeb15a - languageName: node - linkType: hard - "is-data-view@npm:^1.0.1": version: 1.0.1 resolution: "is-data-view@npm:1.0.1" @@ -10154,7 +7168,7 @@ __metadata: languageName: node linkType: hard -"is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": +"is-date-object@npm:^1.0.1": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" dependencies: @@ -10163,35 +7177,6 @@ __metadata: languageName: node linkType: hard -"is-descriptor@npm:^0.1.0": - version: 0.1.7 - resolution: "is-descriptor@npm:0.1.7" - dependencies: - is-accessor-descriptor: ^1.0.1 - is-data-descriptor: ^1.0.1 - checksum: 45743109f0bb03f9fa989c34d31ece87cc15792649f147b896a7c4db2906a02fca685867619f4d312e024d7bbd53b945a47c6830d01f5e73efcc6388ac211963 - languageName: node - linkType: hard - -"is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2": - version: 1.0.3 - resolution: "is-descriptor@npm:1.0.3" - dependencies: - is-accessor-descriptor: ^1.0.1 - is-data-descriptor: ^1.0.1 - checksum: 316153b2fd86ac23b0a2f28b77744ae0a4e3c7a54fe52fa70b125d0971eb0a3bcfb562fa8e74537af0dad5bc405cc606726eb501fc748a241c10910deea89cfb - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - "is-electron@npm:^2.2.0": version: 2.2.2 resolution: "is-electron@npm:2.2.2" @@ -10199,22 +7184,6 @@ __metadata: languageName: node linkType: hard -"is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": - version: 0.1.1 - resolution: "is-extendable@npm:0.1.1" - checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 - languageName: node - linkType: hard - -"is-extendable@npm:^1.0.1": - version: 1.0.1 - resolution: "is-extendable@npm:1.0.1" - dependencies: - is-plain-object: ^2.0.4 - checksum: db07bc1e9de6170de70eff7001943691f05b9d1547730b11be01c0ebfe67362912ba743cf4be6fd20a5e03b4180c685dad80b7c509fe717037e3eee30ad8e84f - languageName: node - linkType: hard - "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -10222,29 +7191,6 @@ __metadata: languageName: node linkType: hard -"is-finite@npm:^1.0.0": - version: 1.1.0 - resolution: "is-finite@npm:1.1.0" - checksum: 532b97ed3d03e04c6bd203984d9e4ba3c0c390efee492bad5d1d1cd1802a68ab27adbd3ef6382f6312bed6c8bb1bd3e325ea79a8dc8fe080ed7a06f5f97b93e7 - languageName: node - linkType: hard - -"is-fn@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fn@npm:1.0.0" - checksum: eeea1e536716f93a92dc1a8550b2c0909fe74bb5144d0fb6d65e0d31eb9c06c30559f69d83a9351d2288cc7293b43bc074e0fab5fae19e312ff38aa0c7672827 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fullwidth-code-point@npm:1.0.0" - dependencies: - number-is-nan: ^1.0.0 - checksum: 4d46a7465a66a8aebcc5340d3b63a56602133874af576a9ca42c6f0f4bd787a743605771c5f246db77da96605fefeffb65fc1dbe862dcc7328f4b4d03edf5a57 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^2.0.0": version: 2.0.0 resolution: "is-fullwidth-code-point@npm:2.0.0" @@ -10259,13 +7205,6 @@ __metadata: languageName: node linkType: hard -"is-function@npm:^1.0.1": - version: 1.0.2 - resolution: "is-function@npm:1.0.2" - checksum: 7d564562e07b4b51359547d3ccc10fb93bb392fd1b8177ae2601ee4982a0ece86d952323fc172a9000743a3971f09689495ab78a1d49a9b14fc97a7e28521dc0 - languageName: node - linkType: hard - "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -10321,15 +7260,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^3.0.0": - version: 3.0.0 - resolution: "is-number@npm:3.0.0" - dependencies: - kind-of: ^3.0.2 - checksum: 0c62bf8e9d72c4dd203a74d8cfc751c746e75513380fef420cda8237e619a988ee43e678ddb23c87ac24d91ac0fe9f22e4ffb1301a50310c697e9d73ca3994e9 - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -10351,16 +7281,7 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": - version: 2.0.4 - resolution: "is-plain-object@npm:2.0.4" - dependencies: - isobject: ^3.0.1 - checksum: 2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca - languageName: node - linkType: hard - -"is-regex@npm:^1.1.4, is-regex@npm:~1.1.4": +"is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" dependencies: @@ -10379,7 +7300,7 @@ __metadata: languageName: node linkType: hard -"is-stream@npm:^1.0.1, is-stream@npm:^1.1.0": +"is-stream@npm:^1.1.0": version: 1.1.0 resolution: "is-stream@npm:1.1.0" checksum: 063c6bec9d5647aa6d42108d4c59723d2bd4ae42135a2d4db6eadbd49b7ea05b750fd69d279e5c7c45cf9da753ad2c00d8978be354d65aa9f6bb434969c6a2ae @@ -10420,7 +7341,7 @@ __metadata: languageName: node linkType: hard -"is-typedarray@npm:^1.0.0, is-typedarray@npm:~1.0.0": +"is-typedarray@npm:~1.0.0": version: 1.0.0 resolution: "is-typedarray@npm:1.0.0" checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 @@ -10441,13 +7362,6 @@ __metadata: languageName: node linkType: hard -"is-utf8@npm:^0.2.0": - version: 0.2.1 - resolution: "is-utf8@npm:0.2.1" - checksum: 167ccd2be869fc228cc62c1a28df4b78c6b5485d15a29027d3b5dceb09b383e86a3522008b56dcac14b592b22f0a224388718c2505027a994fd8471465de54b3 - languageName: node - linkType: hard - "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -10457,22 +7371,6 @@ __metadata: languageName: node linkType: hard -"is-windows@npm:^1.0.2": - version: 1.0.2 - resolution: "is-windows@npm:1.0.2" - checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 - languageName: node - linkType: hard - -"is-wsl@npm:^2.1.1": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: ^2.0.0 - checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - "isarray@npm:0.0.1": version: 0.0.1 resolution: "isarray@npm:0.0.1" @@ -10480,7 +7378,7 @@ __metadata: languageName: node linkType: hard -"isarray@npm:1.0.0, isarray@npm:^1.0.0, isarray@npm:~1.0.0": +"isarray@npm:^1.0.0, isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab @@ -10515,22 +7413,6 @@ __metadata: languageName: node linkType: hard -"isobject@npm:^2.0.0": - version: 2.1.0 - resolution: "isobject@npm:2.1.0" - dependencies: - isarray: 1.0.0 - checksum: 811c6f5a866877d31f0606a88af4a45f282544de886bf29f6a34c46616a1ae2ed17076cc6bf34c0128f33eecf7e1fcaa2c82cf3770560d3e26810894e96ae79f - languageName: node - linkType: hard - -"isobject@npm:^3.0.0, isobject@npm:^3.0.1": - version: 3.0.1 - resolution: "isobject@npm:3.0.1" - checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 - languageName: node - linkType: hard - "isomorphic-unfetch@npm:^3.0.0": version: 3.1.0 resolution: "isomorphic-unfetch@npm:3.1.0" @@ -10674,27 +7556,13 @@ __metadata: languageName: node linkType: hard -"js-sha3@npm:^0.5.7": - version: 0.5.7 - resolution: "js-sha3@npm:0.5.7" - checksum: 973a28ea4b26cc7f12d2ab24f796e24ee4a71eef45a6634a052f6eb38cf8b2333db798e896e6e094ea6fa4dfe8e42a2a7942b425cf40da3f866623fd05bb91ea - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": +"js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 languageName: node linkType: hard -"js-tokens@npm:^3.0.2": - version: 3.0.2 - resolution: "js-tokens@npm:3.0.2" - checksum: ff24cf90e6e4ac446eba56e604781c1aaf3bdaf9b13a00596a0ebd972fa3b25dc83c0f0f67289c33252abb4111e0d14e952a5d9ffb61f5c22532d555ebd8d8a9 - languageName: node - linkType: hard - "js-yaml@npm:3.x, js-yaml@npm:^3.13.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" @@ -10732,24 +7600,6 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^1.3.0": - version: 1.3.0 - resolution: "jsesc@npm:1.3.0" - bin: - jsesc: bin/jsesc - checksum: 9384cc72bf8ef7f2eb75fea64176b8b0c1c5e77604854c72cb4670b7072e112e3baaa69ef134be98cb078834a7812b0bfe676ad441ccd749a59427f5ed2127f1 - languageName: node - linkType: hard - -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" - bin: - jsesc: bin/jsesc - checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 - languageName: node - linkType: hard - "json-bigint@npm:^1.0.0": version: 1.0.0 resolution: "json-bigint@npm:1.0.0" @@ -10759,13 +7609,6 @@ __metadata: languageName: node linkType: hard -"json-buffer@npm:3.0.0": - version: 3.0.0 - resolution: "json-buffer@npm:3.0.0" - checksum: 0cecacb8025370686a916069a2ff81f7d55167421b6aa7270ee74e244012650dd6bce22b0852202ea7ff8624fce50ff0ec1bdf95914ccb4553426e290d5a63fa - languageName: node - linkType: hard - "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -10780,36 +7623,6 @@ __metadata: languageName: node linkType: hard -"json-rpc-engine@npm:^3.4.0, json-rpc-engine@npm:^3.6.0": - version: 3.8.0 - resolution: "json-rpc-engine@npm:3.8.0" - dependencies: - async: ^2.0.1 - babel-preset-env: ^1.7.0 - babelify: ^7.3.0 - json-rpc-error: ^2.0.0 - promise-to-callback: ^1.0.0 - safe-event-emitter: ^1.0.1 - checksum: 4a02ddda196b68717cdcdf9bc8eac91f956b717431daf1f317e016d564bd5b8974e8a66f75fd1f069d63b8e944128020ec7c371f28cf29ac0951d3338b2f667c - languageName: node - linkType: hard - -"json-rpc-error@npm:^2.0.0": - version: 2.0.0 - resolution: "json-rpc-error@npm:2.0.0" - dependencies: - inherits: ^2.0.1 - checksum: bbfb1ff82d0605b4dfd4ac6d093e863a8f623e0e83a098ccab5711a08d2ae09ea603260d4573a524e596701e64733690a5c31901e99daebe05b09053d8702d0c - languageName: node - linkType: hard - -"json-rpc-random-id@npm:^1.0.0": - version: 1.0.1 - resolution: "json-rpc-random-id@npm:1.0.1" - checksum: fcd2e884193a129ace4002bd65a86e9cdb206733b4693baea77bd8b372cf8de3043fbea27716a2c9a716581a908ca8d978d9dfec4847eb2cf77edb4cf4b2252c - languageName: node - linkType: hard - "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -10838,15 +7651,10 @@ __metadata: languageName: node linkType: hard -"json-stable-stringify@npm:^1.0.1": - version: 1.1.1 - resolution: "json-stable-stringify@npm:1.1.1" - dependencies: - call-bind: ^1.0.5 - isarray: ^2.0.5 - jsonify: ^0.0.1 - object-keys: ^1.1.1 - checksum: e1ba06600fd278767eeff53f28e408e29c867e79abf564e7aadc3ce8f31f667258f8db278ef28831e45884dd687388fa1910f46e599fc19fb94c9afbbe3a4de8 +"json-stream-stringify@npm:^3.1.4": + version: 3.1.6 + resolution: "json-stream-stringify@npm:3.1.6" + checksum: ce873e09fe18461960b7536f63e2f913a2cb242819513856ed1af58989d41846976e7177cb1fe3c835220023aa01e534d56b6d5c3290a5b23793a6f4cb93785e languageName: node linkType: hard @@ -10857,15 +7665,6 @@ __metadata: languageName: node linkType: hard -"json5@npm:^0.5.1": - version: 0.5.1 - resolution: "json5@npm:0.5.1" - bin: - json5: lib/cli.js - checksum: 9b85bf06955b23eaa4b7328aa8892e3887e81ca731dd27af04a5f5f1458fbc5e1de57a24442e3272f8a888dd1abe1cb68eb693324035f6b3aeba4fcab7667d62 - languageName: node - linkType: hard - "json5@npm:^1.0.2": version: 1.0.2 resolution: "json5@npm:1.0.2" @@ -10877,18 +7676,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^2.1.0": - version: 2.4.0 - resolution: "jsonfile@npm:2.4.0" - dependencies: - graceful-fs: ^4.1.6 - dependenciesMeta: - graceful-fs: - optional: true - checksum: f5064aabbc9e35530dc471d8b203ae1f40dbe949ddde4391c6f6a6d310619a15f0efdae5587df594d1d70c555193aaeee9d2ed4aec9ffd5767bd5e4e62d49c3d - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -10914,13 +7701,6 @@ __metadata: languageName: node linkType: hard -"jsonify@npm:^0.0.1": - version: 0.0.1 - resolution: "jsonify@npm:0.0.1" - checksum: 027287e1c0294fce15f18c0ff990cfc2318e7f01fb76515f784d5cd0784abfec6fc5c2355c3a2f2cb0ad7f4aa2f5b74ebbfe4e80476c35b2d13cabdb572e1134 - languageName: node - linkType: hard - "jsonparse@npm:^1.2.0": version: 1.3.1 resolution: "jsonparse@npm:1.3.1" @@ -10982,16 +7762,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^3.0.0": - version: 3.1.0 - resolution: "keyv@npm:3.1.0" - dependencies: - json-buffer: 3.0.0 - checksum: bb7e8f3acffdbafbc2dd5b63f377fe6ec4c0e2c44fc82720449ef8ab54f4a7ce3802671ed94c0f475ae0a8549703353a2124561fcf3317010c141b32ca1ce903 - languageName: node - linkType: hard - -"keyv@npm:^4.0.0, keyv@npm:^4.5.3": +"keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -11000,24 +7771,6 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": - version: 3.2.2 - resolution: "kind-of@npm:3.2.2" - dependencies: - is-buffer: ^1.1.5 - checksum: e898df8ca2f31038f27d24f0b8080da7be274f986bc6ed176f37c77c454d76627619e1681f6f9d2e8d2fd7557a18ecc419a6bb54e422abcbb8da8f1a75e4b386 - languageName: node - linkType: hard - -"kind-of@npm:^4.0.0": - version: 4.0.0 - resolution: "kind-of@npm:4.0.0" - dependencies: - is-buffer: ^1.1.5 - checksum: 1b9e7624a8771b5a2489026e820f3bbbcc67893e1345804a56b23a91e9069965854d2a223a7c6ee563c45be9d8c6ff1ef87f28ed5f0d1a8d00d9dcbb067c529f - languageName: node - linkType: hard - "kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -11025,36 +7778,6 @@ __metadata: languageName: node linkType: hard -"klaw-sync@npm:^6.0.0": - version: 6.0.0 - resolution: "klaw-sync@npm:6.0.0" - dependencies: - graceful-fs: ^4.1.11 - checksum: 0da397f8961313c3ef8f79fb63af9002cde5a8fb2aeb1a37351feff0dd6006129c790400c3f5c3b4e757bedcabb13d21ec0a5eaef5a593d59515d4f2c291e475 - languageName: node - linkType: hard - -"klaw@npm:^1.0.0": - version: 1.3.1 - resolution: "klaw@npm:1.3.1" - dependencies: - graceful-fs: ^4.1.9 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 8f69e4797c26e7c3f2426bfa85f38a3da3c2cb1b4c6bd850d2377aed440d41ce9d806f2885c2e2e224372c56af4b1d43b8a499adecf9a05e7373dc6b8b7c52e4 - languageName: node - linkType: hard - -"lcid@npm:^1.0.0": - version: 1.0.0 - resolution: "lcid@npm:1.0.0" - dependencies: - invert-kv: ^1.0.0 - checksum: e8c7a4db07663068c5c44b650938a2bc41aa992037eebb69376214320f202c1250e70b50c32f939e28345fd30c2d35b8e8cd9a19d5932c398246a864ce54843d - languageName: node - linkType: hard - "lcid@npm:^2.0.0": version: 2.0.0 resolution: "lcid@npm:2.0.0" @@ -11073,13 +7796,6 @@ __metadata: languageName: node linkType: hard -"level-codec@npm:~7.0.0": - version: 7.0.1 - resolution: "level-codec@npm:7.0.1" - checksum: 2565c131d93aea0786af5eda9bb907e3f5152fade03fd7a7751e2f95301fc5241063eb927c2f7df086fac33592523aab8df86bcf7ecc46ed53de11453b600329 - languageName: node - linkType: hard - "level-concat-iterator@npm:^3.0.0": version: 3.1.0 resolution: "level-concat-iterator@npm:3.1.0" @@ -11096,15 +7812,6 @@ __metadata: languageName: node linkType: hard -"level-errors@npm:^1.0.3": - version: 1.1.2 - resolution: "level-errors@npm:1.1.2" - dependencies: - errno: ~0.1.1 - checksum: 18c22fd574ff31567642a85d9a306604a32cbe969b8469fee29620c10488214a6b5e6bbf19e3b5e2042859e4b81041af537319c18132a1aaa56d4ed5981157b7 - languageName: node - linkType: hard - "level-errors@npm:^2.0.0, level-errors@npm:~2.0.0": version: 2.0.1 resolution: "level-errors@npm:2.0.1" @@ -11114,49 +7821,6 @@ __metadata: languageName: node linkType: hard -"level-errors@npm:~1.0.3": - version: 1.0.5 - resolution: "level-errors@npm:1.0.5" - dependencies: - errno: ~0.1.1 - checksum: a62df2a24987c0100855ec03f03655ddc6170b33a83987a53858ba0a7dbe125b4b5382e01068a1dc899ccf7f9d12b824702da15488bd06b4b3ee7a1e4232cb0a - languageName: node - linkType: hard - -"level-iterator-stream@npm:^2.0.3": - version: 2.0.3 - resolution: "level-iterator-stream@npm:2.0.3" - dependencies: - inherits: ^2.0.1 - readable-stream: ^2.0.5 - xtend: ^4.0.0 - checksum: dd4211798d032a06ebc3e9c5a3a969b003cb15f1fe6398d9c50c87dc8b0bf8b07197cada253fd7f8c4a933f3c86e12bb041df1561c89b749ac4b991d6e68b17f - languageName: node - linkType: hard - -"level-iterator-stream@npm:~1.3.0": - version: 1.3.1 - resolution: "level-iterator-stream@npm:1.3.1" - dependencies: - inherits: ^2.0.1 - level-errors: ^1.0.3 - readable-stream: ^1.0.33 - xtend: ^4.0.0 - checksum: bf57d8dcee6e7ec68e6c580edc768d2e3960f93e741d7d4adcc7d86f267c741ebcfba5353b3b6551ca10d12e30939c90f1a13303313b1b719325111f0ff14540 - languageName: node - linkType: hard - -"level-iterator-stream@npm:~3.0.0": - version: 3.0.1 - resolution: "level-iterator-stream@npm:3.0.1" - dependencies: - inherits: ^2.0.1 - readable-stream: ^2.3.6 - xtend: ^4.0.0 - checksum: f3348316907c70163ea15319ef7e28c21c6b4b948616e11dcbbb8e3dab9ec5b39f7bf13e0d53f7d23c69641b7a2985a4911c5c9a03bd57a07f1af469aba6e3a8 - languageName: node - linkType: hard - "level-iterator-stream@npm:~4.0.0": version: 4.0.2 resolution: "level-iterator-stream@npm:4.0.2" @@ -11168,16 +7832,6 @@ __metadata: languageName: node linkType: hard -"level-mem@npm:^3.0.1": - version: 3.0.1 - resolution: "level-mem@npm:3.0.1" - dependencies: - level-packager: ~4.0.0 - memdown: ~3.0.0 - checksum: e4c680922afc3c8cd4502d761ab610c8aa7bcacde2550a0a463e1db069eeb55b6b7bec0bb7fda564cec82422944776f9909fe101b0d7746ad8f4f7446ec2a5cd - languageName: node - linkType: hard - "level-mem@npm:^5.0.1": version: 5.0.1 resolution: "level-mem@npm:5.0.1" @@ -11190,48 +7844,11 @@ __metadata: "level-packager@npm:^5.0.3": version: 5.1.1 - resolution: "level-packager@npm:5.1.1" - dependencies: - encoding-down: ^6.3.0 - levelup: ^4.3.2 - checksum: befe2aa54f2010a6ecf7ddce392c8dee225e1839205080a2704d75e560e28b01191b345494696196777b70d376e3eaae4c9e7c330cc70d3000839f5b18dd78f2 - languageName: node - linkType: hard - -"level-packager@npm:~4.0.0": - version: 4.0.1 - resolution: "level-packager@npm:4.0.1" - dependencies: - encoding-down: ~5.0.0 - levelup: ^3.0.0 - checksum: af33054cfdf1f3cb409941c2e6a67190c0437f8b57a518fa1d40d3f9fd75edbb72c2c17595a52b10030fe2d64c8ef474ddb570f925d88402c94cfc95263865cb - languageName: node - linkType: hard - -"level-post@npm:^1.0.7": - version: 1.0.7 - resolution: "level-post@npm:1.0.7" - dependencies: - ltgt: ^2.1.2 - checksum: 27239cfebe2004036d7ed0ace860d03f829f099de62baf727cce53bd99cb06bfc4a202fa7cb828847fa01c421bab13d9d3e79c9554f5cffff681541dda575218 - languageName: node - linkType: hard - -"level-sublevel@npm:6.6.4": - version: 6.6.4 - resolution: "level-sublevel@npm:6.6.4" - dependencies: - bytewise: ~1.1.0 - level-codec: ^9.0.0 - level-errors: ^2.0.0 - level-iterator-stream: ^2.0.3 - ltgt: ~2.1.1 - pull-defer: ^0.2.2 - pull-level: ^2.0.3 - pull-stream: ^3.6.8 - typewiselite: ~1.0.0 - xtend: ~4.0.0 - checksum: 8370e6fbf67bf08daa23de07699d3d2ccf6a349a28db4025a890d4c07857811808372fdf5029c4afedf24e2ff828be6bb7cd9fd0b676090daba38981b2e75cff + resolution: "level-packager@npm:5.1.1" + dependencies: + encoding-down: ^6.3.0 + levelup: ^4.3.2 + checksum: befe2aa54f2010a6ecf7ddce392c8dee225e1839205080a2704d75e560e28b01191b345494696196777b70d376e3eaae4c9e7c330cc70d3000839f5b18dd78f2 languageName: node linkType: hard @@ -11251,27 +7868,6 @@ __metadata: languageName: node linkType: hard -"level-ws@npm:0.0.0": - version: 0.0.0 - resolution: "level-ws@npm:0.0.0" - dependencies: - readable-stream: ~1.0.15 - xtend: ~2.1.1 - checksum: fcc3e6993b538ed8931612a74ef26cf32b53d71c059a819bb1006c075f0c1198afb79026a69aeeafcbd4598c45b4b214315b4216b44eca68587fce1b5ad61b75 - languageName: node - linkType: hard - -"level-ws@npm:^1.0.0": - version: 1.0.0 - resolution: "level-ws@npm:1.0.0" - dependencies: - inherits: ^2.0.3 - readable-stream: ^2.2.8 - xtend: ^4.0.1 - checksum: 752fd0f89eb1ccf811c09de24ca8987437ea84f88e672d0037324fb5d71c5bc022c25ba64d6a00fca33beec48a81e3cd1ef99c2f9fff267b3a4f2233939fad35 - languageName: node - linkType: hard - "level-ws@npm:^2.0.0": version: 2.0.0 resolution: "level-ws@npm:2.0.0" @@ -11295,33 +7891,6 @@ __metadata: languageName: node linkType: hard -"levelup@npm:3.1.1, levelup@npm:^3.0.0": - version: 3.1.1 - resolution: "levelup@npm:3.1.1" - dependencies: - deferred-leveldown: ~4.0.0 - level-errors: ~2.0.0 - level-iterator-stream: ~3.0.0 - xtend: ~4.0.0 - checksum: cddcac2cf5eddcf85ade62efd21f11326cd83559619db6a78696725eac5c5cd16f62d8d49f6594fd3097d9329a1d04847f6d7df23bf4d69f18c16e49afd4a416 - languageName: node - linkType: hard - -"levelup@npm:^1.2.1": - version: 1.3.9 - resolution: "levelup@npm:1.3.9" - dependencies: - deferred-leveldown: ~1.2.1 - level-codec: ~7.0.0 - level-errors: ~1.0.3 - level-iterator-stream: ~1.3.0 - prr: ~1.0.1 - semver: ~5.4.1 - xtend: ~4.0.0 - checksum: df3b534b948c17d724050f6ecc2b21eb2fde357bd0c68582cd3a5eb4bf943a3057cd2e9db6bd7253020fcb853c83a70943bff9264f5132afa8cf3c25c3c7cd8e - languageName: node - linkType: hard - "levelup@npm:^4.3.2": version: 4.4.0 resolution: "levelup@npm:4.4.0" @@ -11362,29 +7931,6 @@ __metadata: languageName: node linkType: hard -"load-json-file@npm:^1.0.0": - version: 1.1.0 - resolution: "load-json-file@npm:1.1.0" - dependencies: - graceful-fs: ^4.1.2 - parse-json: ^2.2.0 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - strip-bom: ^2.0.0 - checksum: 0e4e4f380d897e13aa236246a917527ea5a14e4fc34d49e01ce4e7e2a1e08e2740ee463a03fb021c04f594f29a178f4adb994087549d7c1c5315fcd29bf9934b - languageName: node - linkType: hard - -"locate-path@npm:^2.0.0": - version: 2.0.0 - resolution: "locate-path@npm:2.0.0" - dependencies: - p-locate: ^2.0.0 - path-exists: ^3.0.0 - checksum: 02d581edbbbb0fa292e28d96b7de36b5b62c2fa8b5a7e82638ebb33afa74284acf022d3b1e9ae10e3ffb7658fbc49163fcd5e76e7d1baaa7801c3e05a81da755 - languageName: node - linkType: hard - "locate-path@npm:^3.0.0": version: 3.0.0 resolution: "locate-path@npm:3.0.0" @@ -11404,13 +7950,6 @@ __metadata: languageName: node linkType: hard -"lodash.assign@npm:^4.0.3, lodash.assign@npm:^4.0.6": - version: 4.2.0 - resolution: "lodash.assign@npm:4.2.0" - checksum: 75bbc6733c9f577c448031b4051f990f068802708891f94be9d4c2faffd6a9ec67a2c49671dafc908a068d35687765464853282842b4560b662e6c903d11cc90 - languageName: node - linkType: hard - "lodash.camelcase@npm:^4.3.0": version: 4.3.0 resolution: "lodash.camelcase@npm:4.3.0" @@ -11432,13 +7971,6 @@ __metadata: languageName: node linkType: hard -"lodash.isequalwith@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.isequalwith@npm:4.4.0" - checksum: 428ba7a57c47ec05e2dd18c03a4b4c45dac524a46af7ce3f412594bfc7be6a5acaa51acf9ea113d0002598e9aafc6e19ee8d20bc28363145fcb4d21808c9039f - languageName: node - linkType: hard - "lodash.kebabcase@npm:^4.1.1": version: 4.1.1 resolution: "lodash.kebabcase@npm:4.1.1" @@ -11551,14 +8083,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.20": - version: 4.17.20 - resolution: "lodash@npm:4.17.20" - checksum: b31afa09739b7292a88ec49ffdb2fcaeb41f690def010f7a067eeedffece32da6b6847bfe4d38a77e6f41778b9b2bca75eeab91209936518173271f0b69376ea - languageName: node - linkType: hard - -"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21, lodash@npm:^4.17.4": +"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -11591,31 +8116,6 @@ __metadata: languageName: node linkType: hard -"looper@npm:^2.0.0": - version: 2.0.0 - resolution: "looper@npm:2.0.0" - checksum: ee5124d54c97cd9e778e602e297ed37dd6405b7c36830f90bb1aaa6adb8d64f2a228aa341459e6bf2db9a8d7dc9eb8c16ec9c6bffeab1c47f91efe213858ce36 - languageName: node - linkType: hard - -"looper@npm:^3.0.0": - version: 3.0.0 - resolution: "looper@npm:3.0.0" - checksum: 2ec29b4161e95d33f2257867b0b9ab7f2fef5425582362c966f8f9041a2a6032466b8be159af99323655aca9e6fe1c9da086cf208f6346bd97c9f83ab77ccce0 - languageName: node - linkType: hard - -"loose-envify@npm:^1.0.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: ^3.0.0 || ^4.0.0 - bin: - loose-envify: cli.js - checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 - languageName: node - linkType: hard - "loupe@npm:^2.3.6": version: 2.3.7 resolution: "loupe@npm:2.3.7" @@ -11625,29 +8125,6 @@ __metadata: languageName: node linkType: hard -"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "lowercase-keys@npm:1.0.1" - checksum: 4d045026595936e09953e3867722e309415ff2c80d7701d067546d75ef698dac218a4f53c6d1d0e7368b47e45fd7529df47e6cb56fbb90523ba599f898b3d147 - languageName: node - linkType: hard - -"lowercase-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "lowercase-keys@npm:2.0.0" - checksum: 24d7ebd56ccdf15ff529ca9e08863f3c54b0b9d1edb97a3ae1af34940ae666c01a1e6d200707bce730a8ef76cb57cc10e65f245ecaaf7e6bc8639f2fb460ac23 - languageName: node - linkType: hard - -"lru-cache@npm:5.1.1, lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: ^3.0.2 - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb - languageName: node - linkType: hard - "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": version: 10.3.0 resolution: "lru-cache@npm:10.3.0" @@ -11655,12 +8132,12 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^3.2.0": - version: 3.2.0 - resolution: "lru-cache@npm:3.2.0" +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" dependencies: - pseudomap: ^1.0.1 - checksum: 8e5fb3d7a83401165b8dc9fe16d74828df5754aaeda1061e4f2ea1d0e984b9071a6487f1c3f6f034f935429629f94366abbfb753827ab2977a56b3f5c276e736 + yallist: ^3.0.2 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb languageName: node linkType: hard @@ -11671,20 +8148,13 @@ __metadata: languageName: node linkType: hard -"ltgt@npm:^2.1.2, ltgt@npm:~2.2.0": +"ltgt@npm:~2.2.0": version: 2.2.1 resolution: "ltgt@npm:2.2.1" checksum: 7e3874296f7538bc8087b428ac4208008d7b76916354b34a08818ca7c83958c1df10ec427eeeaad895f6b81e41e24745b18d30f89abcc21d228b94f6961d50a2 languageName: node linkType: hard -"ltgt@npm:~2.1.1": - version: 2.1.3 - resolution: "ltgt@npm:2.1.3" - checksum: b09281f6aeccb34eda52588d21f9116f6e5b7ae1c79f6180bba06edcdcba50de9c6d199be7f817a7ae59819064e3ca7d066fe0bcc67e2458006e4e45cd05cb11 - languageName: node - linkType: hard - "make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -11721,22 +8191,6 @@ __metadata: languageName: node linkType: hard -"map-cache@npm:^0.2.2": - version: 0.2.2 - resolution: "map-cache@npm:0.2.2" - checksum: 3067cea54285c43848bb4539f978a15dedc63c03022abeec6ef05c8cb6829f920f13b94bcaf04142fc6a088318e564c4785704072910d120d55dbc2e0c421969 - languageName: node - linkType: hard - -"map-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "map-visit@npm:1.0.0" - dependencies: - object-visit: ^1.0.0 - checksum: c27045a5021c344fc19b9132eb30313e441863b2951029f8f8b66f79d3d8c1e7e5091578075a996f74e417479506fe9ede28c44ca7bc351a61c9d8073daec36a - languageName: node - linkType: hard - "markdown-table@npm:2.0.0": version: 2.0.0 resolution: "markdown-table@npm:2.0.0" @@ -11746,13 +8200,6 @@ __metadata: languageName: node linkType: hard -"markdown-table@npm:^1.1.3": - version: 1.1.3 - resolution: "markdown-table@npm:1.1.3" - checksum: 292e8c956ae833c2ccb0a55cd8d87980cd657ab11cd9ff63c3fcc4d3a518d3b3882ba07410b8f477ba9e30b3f70658677e4e8acf61816dd6cfdd1f6293130664 - languageName: node - linkType: hard - "mcl-wasm@npm:^0.7.1": version: 0.7.9 resolution: "mcl-wasm@npm:0.7.9" @@ -11771,13 +8218,6 @@ __metadata: languageName: node linkType: hard -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: af1b38516c28ec95d6b0826f6c8f276c58aec391f76be42aa07646b4e39d317723e869700933ca6995b056db4b09a78c92d5440dc23657e6764be5d28874bba1 - languageName: node - linkType: hard - "mem@npm:^4.0.0": version: 4.3.0 resolution: "mem@npm:4.3.0" @@ -11789,20 +8229,6 @@ __metadata: languageName: node linkType: hard -"memdown@npm:^1.0.0": - version: 1.4.1 - resolution: "memdown@npm:1.4.1" - dependencies: - abstract-leveldown: ~2.7.1 - functional-red-black-tree: ^1.0.1 - immediate: ^3.2.3 - inherits: ~2.0.1 - ltgt: ~2.2.0 - safe-buffer: ~5.1.1 - checksum: 3f89142a12389b1ebfc7adaf3be19ed57cd073f84160eb7419b61c8e188e2b82eb787dad168d7b00ca68355b6b952067d9badaa5ac88c8ee014e4b0af2bfaea0 - languageName: node - linkType: hard - "memdown@npm:^5.0.0": version: 5.1.0 resolution: "memdown@npm:5.1.0" @@ -11817,20 +8243,6 @@ __metadata: languageName: node linkType: hard -"memdown@npm:~3.0.0": - version: 3.0.0 - resolution: "memdown@npm:3.0.0" - dependencies: - abstract-leveldown: ~5.0.0 - functional-red-black-tree: ~1.0.1 - immediate: ~3.2.3 - inherits: ~2.0.1 - ltgt: ~2.2.0 - safe-buffer: ~5.1.1 - checksum: 4446fdf7198dcdbae764324200526f41738c9f2a32decb59b5a4dbb1bdfc72e2fc046e9bbe016469ab8a0a52e5d5c8b36bf3829e90dd4674a5f4c961e059d4de - languageName: node - linkType: hard - "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -11838,13 +8250,6 @@ __metadata: languageName: node linkType: hard -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 - languageName: node - linkType: hard - "merge-options@npm:^3.0.4": version: 3.0.4 resolution: "merge-options@npm:3.0.4" @@ -11868,37 +8273,6 @@ __metadata: languageName: node linkType: hard -"merkle-patricia-tree@npm:3.0.0": - version: 3.0.0 - resolution: "merkle-patricia-tree@npm:3.0.0" - dependencies: - async: ^2.6.1 - ethereumjs-util: ^5.2.0 - level-mem: ^3.0.1 - level-ws: ^1.0.0 - readable-stream: ^3.0.6 - rlp: ^2.0.0 - semaphore: ">=1.0.1" - checksum: a500f00e7954eea132309310c48ee2635e9a190e0a775811236a0dc375465ff7e01b230ac0ee213ca13bb995399066719eedb4218e0f47596e9cab79cebc575e - languageName: node - linkType: hard - -"merkle-patricia-tree@npm:^2.1.2, merkle-patricia-tree@npm:^2.3.2": - version: 2.3.2 - resolution: "merkle-patricia-tree@npm:2.3.2" - dependencies: - async: ^1.4.2 - ethereumjs-util: ^5.0.0 - level-ws: 0.0.0 - levelup: ^1.2.1 - memdown: ^1.0.0 - readable-stream: ^2.0.0 - rlp: ^2.0.0 - semaphore: ">=1.0.1" - checksum: f6066a16e08190b9e8d3aa28d8e861a3e884ee0be8109c4f5e879965fdfb8181cfc04bae3aaf97c7fb6d07446d94b4f3e1cce502dde4a5699a03acf6df518b12 - languageName: node - linkType: hard - "merkle-patricia-tree@npm:^4.2.2, merkle-patricia-tree@npm:^4.2.4": version: 4.2.4 resolution: "merkle-patricia-tree@npm:4.2.4" @@ -11913,10 +8287,14 @@ __metadata: languageName: node linkType: hard -"methods@npm:~1.1.2": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a +"micro-eth-signer@npm:^0.14.0": + version: 0.14.0 + resolution: "micro-eth-signer@npm:0.14.0" + dependencies: + "@noble/curves": ~1.8.1 + "@noble/hashes": ~1.7.1 + micro-packed: ~0.7.2 + checksum: 9f49282ed8d0057c77cb65ee87a7c08909cf25ae62676c9ff8006d804bbd882dd2f56956e8589e3716ec7c647a9f308f45810c1f40416873f352a59941a17d7b languageName: node linkType: hard @@ -11927,28 +8305,16 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^3.1.4": - version: 3.1.10 - resolution: "micromatch@npm:3.1.10" +"micro-packed@npm:~0.7.2": + version: 0.7.2 + resolution: "micro-packed@npm:0.7.2" dependencies: - arr-diff: ^4.0.0 - array-unique: ^0.3.2 - braces: ^2.3.1 - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - extglob: ^2.0.4 - fragment-cache: ^0.2.1 - kind-of: ^6.0.2 - nanomatch: ^1.2.9 - object.pick: ^1.3.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.2 - checksum: ad226cba4daa95b4eaf47b2ca331c8d2e038d7b41ae7ed0697cde27f3f1d6142881ab03d4da51b65d9d315eceb5e4cdddb3fbb55f5f72cfa19cf3ea469d054dc + "@scure/base": ~1.2.2 + checksum: 7b9a102fe245f1902614aadf250e5d1a28caea070ad5b79fef9a449f021c5a5e2030ac3f43de7e657ec46283de0bb892a568024189064b71ecc2e9bc5efee684 languageName: node linkType: hard -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4": +"micromatch@npm:^4.0.4": version: 4.0.7 resolution: "micromatch@npm:4.0.7" dependencies: @@ -11977,7 +8343,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.16, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:~2.1.19": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -11986,15 +8352,6 @@ __metadata: languageName: node linkType: hard -"mime@npm:1.6.0": - version: 1.6.0 - resolution: "mime@npm:1.6.0" - bin: - mime: cli.js - checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 - languageName: node - linkType: hard - "mimic-fn@npm:^2.0.0, mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -12002,29 +8359,6 @@ __metadata: languageName: node linkType: hard -"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": - version: 1.0.1 - resolution: "mimic-response@npm:1.0.1" - checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 - languageName: node - linkType: hard - -"mimic-response@npm:^3.1.0": - version: 3.1.0 - resolution: "mimic-response@npm:3.1.0" - checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 - languageName: node - linkType: hard - -"min-document@npm:^2.19.0": - version: 2.19.0 - resolution: "min-document@npm:2.19.0" - dependencies: - dom-walk: ^0.1.0 - checksum: da6437562ea2228041542a2384528e74e22d1daa1a4ec439c165abf0b9d8a63e17e3b8a6dc6e0c731845e85301198730426932a0e813d23f932ca668340c9623 - languageName: node - linkType: hard - "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -12075,7 +8409,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7, minimist@npm:~1.2.8": +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -12133,16 +8467,6 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^2.6.0, minipass@npm:^2.9.0": - version: 2.9.0 - resolution: "minipass@npm:2.9.0" - dependencies: - safe-buffer: ^5.1.2 - yallist: ^3.0.0 - checksum: 077b66f31ba44fd5a0d27d12a9e6a86bff8f97a4978dedb0373167156b5599fadb6920fdde0d9f803374164d810e05e8462ce28e86abbf7f0bea293a93711fc6 - languageName: node - linkType: hard - "minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" @@ -12166,15 +8490,6 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^1.3.3": - version: 1.3.3 - resolution: "minizlib@npm:1.3.3" - dependencies: - minipass: ^2.9.0 - checksum: b0425c04d2ae6aad5027462665f07cc0d52075f7fa16e942b4611115f9b31f02924073b7221be6f75929d3c47ab93750c63f6dc2bbe8619ceacb3de1f77732c0 - languageName: node - linkType: hard - "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -12185,35 +8500,7 @@ __metadata: languageName: node linkType: hard -"mixin-deep@npm:^1.2.0": - version: 1.3.2 - resolution: "mixin-deep@npm:1.3.2" - dependencies: - for-in: ^1.0.2 - is-extendable: ^1.0.1 - checksum: 820d5a51fcb7479f2926b97f2c3bb223546bc915e6b3a3eb5d906dda871bba569863595424a76682f2b15718252954644f3891437cb7e3f220949bed54b1750d - languageName: node - linkType: hard - -"mkdirp-promise@npm:^5.0.1": - version: 5.0.1 - resolution: "mkdirp-promise@npm:5.0.1" - dependencies: - mkdirp: "*" - checksum: 31ddc9478216adf6d6bee9ea7ce9ccfe90356d9fcd1dfb18128eac075390b4161356d64c3a7b0a75f9de01a90aadd990a0ec8c7434036563985c4b853a053ee2 - languageName: node - linkType: hard - -"mkdirp@npm:*": - version: 3.0.1 - resolution: "mkdirp@npm:3.0.1" - bin: - mkdirp: dist/cjs/src/bin.js - checksum: 972deb188e8fb55547f1e58d66bd6b4a3623bf0c7137802582602d73e6480c1c2268dcbafbfb1be466e00cc7e56ac514d7fd9334b7cf33e3e2ab547c16f83a8d - languageName: node - linkType: hard - -"mkdirp@npm:0.5.x, mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.5": +"mkdirp@npm:0.5.x, mkdirp@npm:^0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -12273,27 +8560,6 @@ __metadata: languageName: node linkType: hard -"mock-fs@npm:^4.1.0": - version: 4.14.0 - resolution: "mock-fs@npm:4.14.0" - checksum: dccd976a8d753e19d3c7602ea422d1f7137def3c1128c177e1f5500fe8c50ec15fe0937cfc3a15c4577fe7adb9a37628b92da9294d13d90f08be4b669b0fca76 - languageName: node - linkType: hard - -"mock-property@npm:~1.0.0": - version: 1.0.3 - resolution: "mock-property@npm:1.0.3" - dependencies: - define-data-property: ^1.1.1 - functions-have-names: ^1.2.3 - gopd: ^1.0.1 - has-property-descriptors: ^1.0.0 - hasown: ^2.0.0 - isarray: ^2.0.5 - checksum: 835b106e38580c929def6803dad58fc8299d77ed876faed0098f9eb2076e30a2ef36fb5098adac87a4901c13532de86a859e63c8b6769fb7527e1dbbb6430cce - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -12338,45 +8604,6 @@ __metadata: languageName: node linkType: hard -"multibase@npm:^0.7.0": - version: 0.7.0 - resolution: "multibase@npm:0.7.0" - dependencies: - base-x: ^3.0.8 - buffer: ^5.5.0 - checksum: 3a520897d706b3064b59ddee286a9e1a5b35bb19bd830f93d7ddecdbf69fa46648c8fda0fec49a5d4640b8b7ac9d5fe360417d6de2906599aa535f55bf6b8e58 - languageName: node - linkType: hard - -"multibase@npm:~0.6.0": - version: 0.6.1 - resolution: "multibase@npm:0.6.1" - dependencies: - base-x: ^3.0.8 - buffer: ^5.5.0 - checksum: 0e25a978d2b5cf73e4cce31d032bad85230ea99e9394d259210f676a76539316e7c51bd7dcc9d83523ec7ea1f0e7a3353c5f69397639d78be9acbefa29431faa - languageName: node - linkType: hard - -"multicodec@npm:^0.5.5": - version: 0.5.7 - resolution: "multicodec@npm:0.5.7" - dependencies: - varint: ^5.0.0 - checksum: 5af1febc3bb5381c303c964a4c3bacb9d0d16615599426d58c68722c46e66a7085082995479943084322028324ad692cd70ea14b5eefb2791d325fa00ead04a3 - languageName: node - linkType: hard - -"multicodec@npm:^1.0.0": - version: 1.0.4 - resolution: "multicodec@npm:1.0.4" - dependencies: - buffer: ^5.6.0 - varint: ^5.0.0 - checksum: e6a2916fa76c023b1c90b32ae74f8a781cf0727f71660b245a5ed1db46add6f2ce1586bee5713b16caf0a724e81bfe0678d89910c20d3bb5fd9649dacb2be79e - languageName: node - linkType: hard - "multiformats@npm:^9.4.13, multiformats@npm:^9.4.2, multiformats@npm:^9.4.5, multiformats@npm:^9.5.4": version: 9.9.0 resolution: "multiformats@npm:9.9.0" @@ -12384,17 +8611,6 @@ __metadata: languageName: node linkType: hard -"multihashes@npm:^0.4.15, multihashes@npm:~0.4.15": - version: 0.4.21 - resolution: "multihashes@npm:0.4.21" - dependencies: - buffer: ^5.5.0 - multibase: ^0.7.0 - varint: ^5.0.0 - checksum: 688731560cf7384e899dc75c0da51e426eb7d058c5ea5eb57b224720a1108deb8797f1cd7f45599344d512d2877de99dd6a7b7773a095812365dea4ffe6ebd4c - languageName: node - linkType: hard - "mustache@npm:^4.2.0": version: 4.2.0 resolution: "mustache@npm:4.2.0" @@ -12411,13 +8627,6 @@ __metadata: languageName: node linkType: hard -"nano-json-stream-parser@npm:^0.1.2": - version: 0.1.2 - resolution: "nano-json-stream-parser@npm:0.1.2" - checksum: 5bfe146358c659e0aa7d5e0003416be929c9bd02ba11b1e022b78dddf25be655e33d810249c1687d2c9abdcee5cd4d00856afd1b266a5a127236c0d16416d33a - languageName: node - linkType: hard - "nanoid@npm:^3.0.2, nanoid@npm:^3.1.20, nanoid@npm:^3.1.23": version: 3.3.7 resolution: "nanoid@npm:3.3.7" @@ -12427,25 +8636,6 @@ __metadata: languageName: node linkType: hard -"nanomatch@npm:^1.2.9": - version: 1.2.13 - resolution: "nanomatch@npm:1.2.13" - dependencies: - arr-diff: ^4.0.0 - array-unique: ^0.3.2 - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - fragment-cache: ^0.2.1 - is-windows: ^1.0.2 - kind-of: ^6.0.2 - object.pick: ^1.3.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8 - languageName: node - linkType: hard - "napi-macros@npm:~2.0.0": version: 2.0.0 resolution: "napi-macros@npm:2.0.0" @@ -12485,7 +8675,7 @@ __metadata: languageName: node linkType: hard -"negotiator@npm:0.6.3, negotiator@npm:^0.6.3": +"negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 @@ -12499,13 +8689,6 @@ __metadata: languageName: node linkType: hard -"next-tick@npm:^1.1.0": - version: 1.1.0 - resolution: "next-tick@npm:1.1.0" - checksum: 83b5cf36027a53ee6d8b7f9c0782f2ba87f4858d977342bfc3c20c21629290a2111f8374d13a81221179603ffc4364f38374b5655d17b6a8f8a8c77bdea4fe8b - languageName: node - linkType: hard - "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -12531,7 +8714,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.3.0, node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.8": +"node-fetch@npm:^2.3.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.8": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -12545,16 +8728,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:~1.7.1": - version: 1.7.3 - resolution: "node-fetch@npm:1.7.3" - dependencies: - encoding: ^0.1.11 - is-stream: ^1.0.1 - checksum: 3bb0528c05d541316ebe52770d71ee25a6dce334df4231fd55df41a644143e07f068637488c18a5b0c43f05041dbd3346752f9e19b50df50569a802484544d5b - languageName: node - linkType: hard - "node-gyp-build@npm:4.3.0": version: 4.3.0 resolution: "node-gyp-build@npm:4.3.0" @@ -12637,36 +8810,10 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^2.3.2": - version: 2.5.0 - resolution: "normalize-package-data@npm:2.5.0" - dependencies: - hosted-git-info: ^2.1.4 - resolve: ^1.10.0 - semver: 2 || 3 || 4 || 5 - validate-npm-package-license: ^3.0.1 - checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 - languageName: node - linkType: hard - "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" - checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 - languageName: node - linkType: hard - -"normalize-url@npm:^4.1.0": - version: 4.5.1 - resolution: "normalize-url@npm:4.5.1" - checksum: 9a9dee01df02ad23e171171893e56e22d752f7cff86fb96aafeae074819b572ea655b60f8302e2d85dbb834dc885c972cc1c573892fea24df46b2765065dd05a - languageName: node - linkType: hard - -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 + checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 languageName: node linkType: hard @@ -12688,13 +8835,6 @@ __metadata: languageName: node linkType: hard -"number-is-nan@npm:^1.0.0": - version: 1.0.1 - resolution: "number-is-nan@npm:1.0.1" - checksum: 13656bc9aa771b96cef209ffca31c31a03b507ca6862ba7c3f638a283560620d723d52e626d57892c7fff475f4c36ac07f0600f14544692ff595abff214b9ffb - languageName: node - linkType: hard - "number-to-bn@npm:1.7.0": version: 1.7.0 resolution: "number-to-bn@npm:1.7.0" @@ -12712,24 +8852,13 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4, object-assign@npm:^4.0.0, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": +"object-assign@npm:^4.1.0": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f languageName: node linkType: hard -"object-copy@npm:^0.1.0": - version: 0.1.0 - resolution: "object-copy@npm:0.1.0" - dependencies: - copy-descriptor: ^0.1.0 - define-property: ^0.2.5 - kind-of: ^3.0.3 - checksum: a9e35f07e3a2c882a7e979090360d1a20ab51d1fa19dfdac3aa8873b328a7c4c7683946ee97c824ae40079d848d6740a3788fa14f2185155dab7ed970a72c783 - languageName: node - linkType: hard - "object-inspect@npm:^1.13.1": version: 1.13.2 resolution: "object-inspect@npm:1.13.2" @@ -12737,23 +8866,6 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:~1.12.3": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db - languageName: node - linkType: hard - -"object-is@npm:^1.1.5": - version: 1.1.6 - resolution: "object-is@npm:1.1.6" - dependencies: - call-bind: ^1.0.7 - define-properties: ^1.2.1 - checksum: 3ea22759967e6f2380a2cbbd0f737b42dc9ddb2dfefdb159a1b927fea57335e1b058b564bfa94417db8ad58cddab33621a035de6f5e5ad56d89f2dd03e66c6a1 - languageName: node - linkType: hard - "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -12761,22 +8873,6 @@ __metadata: languageName: node linkType: hard -"object-keys@npm:~0.4.0": - version: 0.4.0 - resolution: "object-keys@npm:0.4.0" - checksum: 1be3ebe9b48c0d5eda8e4a30657d887a748cb42435e0e2eaf49faf557bdd602cd2b7558b8ce90a4eb2b8592d16b875a1900bce859cbb0f35b21c67e11a45313c - languageName: node - linkType: hard - -"object-visit@npm:^1.0.0": - version: 1.0.1 - resolution: "object-visit@npm:1.0.1" - dependencies: - isobject: ^3.0.0 - checksum: b0ee07f5bf3bb881b881ff53b467ebbde2b37ebb38649d6944a6cd7681b32eedd99da9bd1e01c55facf81f54ed06b13af61aba6ad87f0052982995e09333f790 - languageName: node - linkType: hard - "object.assign@npm:^4.1.5": version: 4.1.5 resolution: "object.assign@npm:4.1.5" @@ -12801,21 +8897,6 @@ __metadata: languageName: node linkType: hard -"object.getownpropertydescriptors@npm:^2.1.6": - version: 2.1.8 - resolution: "object.getownpropertydescriptors@npm:2.1.8" - dependencies: - array.prototype.reduce: ^1.0.6 - call-bind: ^1.0.7 - define-properties: ^1.2.1 - es-abstract: ^1.23.2 - es-object-atoms: ^1.0.0 - gopd: ^1.0.1 - safe-array-concat: ^1.1.2 - checksum: 073e492700a7f61ff6c471a2ed96e72473b030a7a105617f03cab192fb4bbc0e6068ef76534ec56afd34baf26b5dc5408de59cb0140ec8abde781e00faa3e63e - languageName: node - linkType: hard - "object.groupby@npm:^1.0.1": version: 1.0.3 resolution: "object.groupby@npm:1.0.3" @@ -12827,15 +8908,6 @@ __metadata: languageName: node linkType: hard -"object.pick@npm:^1.3.0": - version: 1.3.0 - resolution: "object.pick@npm:1.3.0" - dependencies: - isobject: ^3.0.1 - checksum: 77fb6eed57c67adf75e9901187e37af39f052ef601cb4480386436561357eb9e459e820762f01fd02c5c1b42ece839ad393717a6d1850d848ee11fbabb3e580a - languageName: node - linkType: hard - "object.values@npm:^1.1.7": version: 1.2.0 resolution: "object.values@npm:1.2.0" @@ -12854,24 +8926,6 @@ __metadata: languageName: node linkType: hard -"oboe@npm:2.1.4": - version: 2.1.4 - resolution: "oboe@npm:2.1.4" - dependencies: - http-https: ^1.0.0 - checksum: b9172453fba362aec86c45d7bcb4f512302bb23ef34c7c9c498974dc4e7ec0e298931bac5a093445fd946d5604e5dd16563e2d2ae922101ac4b47be2e18e30cc - languageName: node - linkType: hard - -"on-finished@npm:2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: 1.1.1 - checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 - languageName: node - linkType: hard - "once@npm:1.x, once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -12890,16 +8944,6 @@ __metadata: languageName: node linkType: hard -"open@npm:^7.4.2": - version: 7.4.2 - resolution: "open@npm:7.4.2" - dependencies: - is-docker: ^2.0.0 - is-wsl: ^2.1.1 - checksum: 3333900ec0e420d64c23b831bc3467e57031461d843c801f569b2204a1acc3cd7b3ec3c7897afc9dde86491dfa289708eb92bba164093d8bd88fb2c231843c91 - languageName: node - linkType: hard - "opencollective-postinstall@npm:^2.0.0": version: 2.0.3 resolution: "opencollective-postinstall@npm:2.0.3" @@ -12960,22 +9004,6 @@ __metadata: languageName: node linkType: hard -"os-homedir@npm:^1.0.0": - version: 1.0.2 - resolution: "os-homedir@npm:1.0.2" - checksum: af609f5a7ab72de2f6ca9be6d6b91a599777afc122ac5cad47e126c1f67c176fe9b52516b9eeca1ff6ca0ab8587fe66208bc85e40a3940125f03cdb91408e9d2 - languageName: node - linkType: hard - -"os-locale@npm:^1.4.0": - version: 1.4.0 - resolution: "os-locale@npm:1.4.0" - dependencies: - lcid: ^1.0.0 - checksum: 0161a1b6b5a8492f99f4b47fe465df9fc521c55ba5414fce6444c45e2500487b8ed5b40a47a98a2363fe83ff04ab033785300ed8df717255ec4c3b625e55b1fb - languageName: node - linkType: hard - "os-locale@npm:^3.1.0": version: 3.1.0 resolution: "os-locale@npm:3.1.0" @@ -12987,27 +9015,13 @@ __metadata: languageName: node linkType: hard -"os-tmpdir@npm:^1.0.1, os-tmpdir@npm:~1.0.2": +"os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" checksum: 5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d languageName: node linkType: hard -"p-cancelable@npm:^1.0.0": - version: 1.1.0 - resolution: "p-cancelable@npm:1.1.0" - checksum: 2db3814fef6d9025787f30afaee4496a8857a28be3c5706432cbad76c688a6db1874308f48e364a42f5317f5e41e8e7b4f2ff5c8ff2256dbb6264bc361704ece - languageName: node - linkType: hard - -"p-cancelable@npm:^2.0.0": - version: 2.1.1 - resolution: "p-cancelable@npm:2.1.1" - checksum: 3dba12b4fb4a1e3e34524535c7858fc82381bbbd0f247cc32dedc4018592a3950ce66b106d0880b4ec4c2d8d6576f98ca885dc1d7d0f274d1370be20e9523ddf - languageName: node - linkType: hard - "p-defer@npm:^1.0.0": version: 1.0.0 resolution: "p-defer@npm:1.0.0" @@ -13053,15 +9067,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^1.1.0": - version: 1.3.0 - resolution: "p-limit@npm:1.3.0" - dependencies: - p-try: ^1.0.0 - checksum: 281c1c0b8c82e1ac9f81acd72a2e35d402bf572e09721ce5520164e9de07d8274451378a3470707179ad13240535558f4b277f02405ad752e08c7d5b0d54fbfd - languageName: node - linkType: hard - "p-limit@npm:^2.0.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -13080,15 +9085,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^2.0.0": - version: 2.0.0 - resolution: "p-locate@npm:2.0.0" - dependencies: - p-limit: ^1.1.0 - checksum: e2dceb9b49b96d5513d90f715780f6f4972f46987dc32a0e18bc6c3fc74a1a5d73ec5f81b1398af5e58b99ea1ad03fd41e9181c01fa81b4af2833958696e3081 - languageName: node - linkType: hard - "p-locate@npm:^3.0.0": version: 3.0.0 resolution: "p-locate@npm:3.0.0" @@ -13116,13 +9112,6 @@ __metadata: languageName: node linkType: hard -"p-try@npm:^1.0.0": - version: 1.0.0 - resolution: "p-try@npm:1.0.0" - checksum: 3b5303f77eb7722144154288bfd96f799f8ff3e2b2b39330efe38db5dd359e4fb27012464cd85cb0a76e9b7edd1b443568cb3192c22e7cffc34989df0bafd605 - languageName: node - linkType: hard - "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" @@ -13146,27 +9135,6 @@ __metadata: languageName: node linkType: hard -"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.7": - version: 5.1.7 - resolution: "parse-asn1@npm:5.1.7" - dependencies: - asn1.js: ^4.10.1 - browserify-aes: ^1.2.0 - evp_bytestokey: ^1.0.3 - hash-base: ~3.0 - pbkdf2: ^3.1.2 - safe-buffer: ^5.2.1 - checksum: 93c7194c1ed63a13e0b212d854b5213ad1aca0ace41c66b311e97cca0519cf9240f79435a0306a3b412c257f0ea3f1953fd0d9549419a0952c9e995ab361fd6c - languageName: node - linkType: hard - -"parse-cache-control@npm:^1.0.1": - version: 1.0.1 - resolution: "parse-cache-control@npm:1.0.1" - checksum: 5a70868792124eb07c2dd07a78fcb824102e972e908254e9e59ce59a4796c51705ff28196d2b20d3b7353d14e9f98e65ed0e4eda9be072cc99b5297dc0466fee - languageName: node - linkType: hard - "parse-duration@npm:^1.0.0": version: 1.1.0 resolution: "parse-duration@npm:1.1.0" @@ -13174,22 +9142,6 @@ __metadata: languageName: node linkType: hard -"parse-headers@npm:^2.0.0": - version: 2.0.5 - resolution: "parse-headers@npm:2.0.5" - checksum: 3e97f01e4c7f960bfbfd0ee489f0bd8d3c72b6c814f1f79b66abec2cca8eaf8e4ecd89deba0b6e61266469aed87350bc932001181c01ff8c29a59e696abe251f - languageName: node - linkType: hard - -"parse-json@npm:^2.2.0": - version: 2.2.0 - resolution: "parse-json@npm:2.2.0" - dependencies: - error-ex: ^1.2.0 - checksum: dda78a63e57a47b713a038630868538f718a7ca0cd172a36887b0392ccf544ed0374902eb28f8bf3409e8b71d62b79d17062f8543afccf2745f9b0b2d2bb80ca - languageName: node - linkType: hard - "parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -13202,66 +9154,6 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:~1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 - languageName: node - linkType: hard - -"pascalcase@npm:^0.1.1": - version: 0.1.1 - resolution: "pascalcase@npm:0.1.1" - checksum: f83681c3c8ff75fa473a2bb2b113289952f802ff895d435edd717e7cb898b0408cbdb247117a938edcbc5d141020909846cc2b92c47213d764e2a94d2ad2b925 - languageName: node - linkType: hard - -"patch-package@npm:6.2.2": - version: 6.2.2 - resolution: "patch-package@npm:6.2.2" - dependencies: - "@yarnpkg/lockfile": ^1.1.0 - chalk: ^2.4.2 - cross-spawn: ^6.0.5 - find-yarn-workspace-root: ^1.2.1 - fs-extra: ^7.0.1 - is-ci: ^2.0.0 - klaw-sync: ^6.0.0 - minimist: ^1.2.0 - rimraf: ^2.6.3 - semver: ^5.6.0 - slash: ^2.0.0 - tmp: ^0.0.33 - bin: - patch-package: index.js - checksum: 5e2f49457b0dc56b5ce0a9d23e281e062e9f225d87a832540f02ffed29ffa7f298b1877daf13c16500ef8a759109c975e3d28d6bd63b0d953f349177abee1767 - languageName: node - linkType: hard - -"patch-package@npm:^6.2.2": - version: 6.5.1 - resolution: "patch-package@npm:6.5.1" - dependencies: - "@yarnpkg/lockfile": ^1.1.0 - chalk: ^4.1.2 - cross-spawn: ^6.0.5 - find-yarn-workspace-root: ^2.0.0 - fs-extra: ^9.0.0 - is-ci: ^2.0.0 - klaw-sync: ^6.0.0 - minimist: ^1.2.6 - open: ^7.4.2 - rimraf: ^2.6.3 - semver: ^5.6.0 - slash: ^2.0.0 - tmp: ^0.0.33 - yaml: ^1.10.2 - bin: - patch-package: index.js - checksum: 8530ffa30f11136b527c6eddf6da48fa12856ee510a47edb1f9cdf8a025636adb82968f5fae778b5e04ce8c87915ebdf5911422b54add59a5a42e372a8f30eb2 - languageName: node - linkType: hard - "path-browserify@npm:^1.0.0": version: 1.0.1 resolution: "path-browserify@npm:1.0.1" @@ -13269,15 +9161,6 @@ __metadata: languageName: node linkType: hard -"path-exists@npm:^2.0.0": - version: 2.1.0 - resolution: "path-exists@npm:2.1.0" - dependencies: - pinkie-promise: ^2.0.0 - checksum: fdb734f1d00f225f7a0033ce6d73bff6a7f76ea08936abf0e5196fa6e54a645103538cd8aedcb90d6d8c3fa3705ded0c58a4da5948ae92aa8834892c1ab44a84 - languageName: node - linkType: hard - "path-exists@npm:^3.0.0": version: 3.0.0 resolution: "path-exists@npm:3.0.0" @@ -13292,7 +9175,7 @@ __metadata: languageName: node linkType: hard -"path-is-absolute@npm:^1.0.0, path-is-absolute@npm:^1.0.1": +"path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 @@ -13330,24 +9213,6 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce - languageName: node - linkType: hard - -"path-type@npm:^1.0.0": - version: 1.1.0 - resolution: "path-type@npm:1.1.0" - dependencies: - graceful-fs: ^4.1.2 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - checksum: 59a4b2c0e566baf4db3021a1ed4ec09a8b36fca960a490b54a6bcefdb9987dafe772852982b6011cd09579478a96e57960a01f75fa78a794192853c9d468fc79 - languageName: node - linkType: hard - "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -13362,7 +9227,7 @@ __metadata: languageName: node linkType: hard -"pbkdf2@npm:^3.0.17, pbkdf2@npm:^3.0.3, pbkdf2@npm:^3.0.9, pbkdf2@npm:^3.1.2": +"pbkdf2@npm:^3.0.17, pbkdf2@npm:^3.0.9": version: 3.1.2 resolution: "pbkdf2@npm:3.1.2" dependencies: @@ -13389,6 +9254,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.0": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -13396,10 +9268,10 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.0.0, pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: a7a5188c954f82c6585720e9143297ccd0e35ad8072231608086ca950bee672d51b0ef676254af0788205e59bd4e4deb4e7708769226bed725bf13370a7d1464 languageName: node linkType: hard @@ -13410,22 +9282,6 @@ __metadata: languageName: node linkType: hard -"pinkie-promise@npm:^2.0.0": - version: 2.0.1 - resolution: "pinkie-promise@npm:2.0.1" - dependencies: - pinkie: ^2.0.0 - checksum: b53a4a2e73bf56b6f421eef711e7bdcb693d6abb474d57c5c413b809f654ba5ee750c6a96dd7225052d4b96c4d053cdcb34b708a86fceed4663303abee52fcca - languageName: node - linkType: hard - -"pinkie@npm:^2.0.0": - version: 2.0.4 - resolution: "pinkie@npm:2.0.4" - checksum: b12b10afea1177595aab036fc220785488f67b4b0fc49e7a27979472592e971614fa1c728e63ad3e7eb748b4ec3c3dbd780819331dad6f7d635c77c10537b9db - languageName: node - linkType: hard - "pkginfo@npm:^0.4.1": version: 0.4.1 resolution: "pkginfo@npm:0.4.1" @@ -13440,13 +9296,6 @@ __metadata: languageName: node linkType: hard -"posix-character-classes@npm:^0.1.0": - version: 0.1.1 - resolution: "posix-character-classes@npm:0.1.1" - checksum: dedb99913c60625a16050cfed2fb5c017648fc075be41ac18474e1c6c3549ef4ada201c8bd9bd006d36827e289c571b6092e1ef6e756cdbab2fd7046b25c6442 - languageName: node - linkType: hard - "possible-typed-array-names@npm:^1.0.0": version: 1.0.0 resolution: "possible-typed-array-names@npm:1.0.0" @@ -13454,20 +9303,6 @@ __metadata: languageName: node linkType: hard -"postinstall-postinstall@npm:^2.1.0": - version: 2.1.0 - resolution: "postinstall-postinstall@npm:2.1.0" - checksum: e1d34252cf8d2c5641c7d2db7426ec96e3d7a975f01c174c68f09ef5b8327bc8d5a9aa2001a45e693db2cdbf69577094d3fe6597b564ad2d2202b65fba76134b - languageName: node - linkType: hard - -"precond@npm:0.2": - version: 0.2.3 - resolution: "precond@npm:0.2.3" - checksum: c613e7d68af3e0b43a294a994bf067cc2bc44b03fd17bc4fb133e30617a4f5b49414b08e9b392d52d7c6822d8a71f66a7fe93a8a1e7d02240177202cff3f63ef - languageName: node - linkType: hard - "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -13482,13 +9317,6 @@ __metadata: languageName: node linkType: hard -"prepend-http@npm:^2.0.0": - version: 2.0.0 - resolution: "prepend-http@npm:2.0.0" - checksum: 7694a9525405447662c1ffd352fcb41b6410c705b739b6f4e3a3e21cf5fdede8377890088e8934436b8b17ba55365a615f153960f30877bf0d0392f9e93503ea - languageName: node - linkType: hard - "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -13520,7 +9348,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.1.2, prettier@npm:^2.3.1, prettier@npm:^2.7.1, prettier@npm:^2.8.3": +"prettier@npm:^2.3.1, prettier@npm:^2.7.1, prettier@npm:^2.8.3": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -13529,13 +9357,6 @@ __metadata: languageName: node linkType: hard -"private@npm:^0.1.6, private@npm:^0.1.8": - version: 0.1.8 - resolution: "private@npm:0.1.8" - checksum: a00abd713d25389f6de7294f0e7879b8a5d09a9ec5fd81cc2f21b29d4f9a80ec53bc4222927d3a281d4aadd4cd373d9a28726fca3935921950dc75fd71d1fdbb - languageName: node - linkType: hard - "proc-log@npm:^3.0.0": version: 3.0.0 resolution: "proc-log@npm:3.0.0" @@ -13557,13 +9378,6 @@ __metadata: languageName: node linkType: hard -"process@npm:^0.11.10": - version: 0.11.10 - resolution: "process@npm:0.11.10" - checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3 - languageName: node - linkType: hard - "progress@npm:^2.0.0": version: 2.0.3 resolution: "progress@npm:2.0.3" @@ -13581,25 +9395,6 @@ __metadata: languageName: node linkType: hard -"promise-to-callback@npm:^1.0.0": - version: 1.0.0 - resolution: "promise-to-callback@npm:1.0.0" - dependencies: - is-fn: ^1.0.0 - set-immediate-shim: ^1.0.1 - checksum: 8c9e1327386e00f799589cdf96fff2586a13b52b0185222bc3199e1305ba9344589eedfd4038dcbaf5592d85d567097d1507b81e948b7fff6ffdd3de49d54e14 - languageName: node - linkType: hard - -"promise@npm:^8.0.0": - version: 8.3.0 - resolution: "promise@npm:8.3.0" - dependencies: - asap: ~2.0.6 - checksum: a69f0ddbddf78ffc529cffee7ad950d307347615970564b17988ce43fbe767af5c738a9439660b24a9a8cbea106c0dcbb6c2b20e23b7e96a8e89e5c2679e94d5 - languageName: node - linkType: hard - "proper-lockfile@npm:^4.1.1": version: 4.1.2 resolution: "proper-lockfile@npm:4.1.2" @@ -13624,128 +9419,35 @@ __metadata: "@protobufjs/inquire": ^1.1.0 "@protobufjs/path": ^1.1.2 "@protobufjs/pool": ^1.1.0 - "@protobufjs/utf8": ^1.1.0 - "@types/long": ^4.0.1 - "@types/node": ">=13.7.0" - long: ^4.0.0 - bin: - pbjs: bin/pbjs - pbts: bin/pbts - checksum: b2fc6a01897b016c2a7e43a854ab4a3c57080f61be41e552235436e7a730711b8e89e47cb4ae52f0f065b5ab5d5989fc932f390337ce3a8ccf07203415700850 - languageName: node - linkType: hard - -"proxy-addr@npm:~2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 - languageName: node - linkType: hard - -"prr@npm:~1.0.1": - version: 1.0.1 - resolution: "prr@npm:1.0.1" - checksum: 3bca2db0479fd38f8c4c9439139b0c42dcaadcc2fbb7bb8e0e6afaa1383457f1d19aea9e5f961d5b080f1cfc05bfa1fe9e45c97a1d3fd6d421950a73d3108381 - languageName: node - linkType: hard - -"pseudomap@npm:^1.0.1": - version: 1.0.2 - resolution: "pseudomap@npm:1.0.2" - checksum: 856c0aae0ff2ad60881168334448e898ad7a0e45fe7386d114b150084254c01e200c957cf378378025df4e052c7890c5bd933939b0e0d2ecfcc1dc2f0b2991f5 - languageName: node - linkType: hard - -"psl@npm:^1.1.28": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d - languageName: node - linkType: hard - -"public-encrypt@npm:^4.0.0": - version: 4.0.3 - resolution: "public-encrypt@npm:4.0.3" - dependencies: - bn.js: ^4.1.0 - browserify-rsa: ^4.0.0 - create-hash: ^1.1.0 - parse-asn1: ^5.0.0 - randombytes: ^2.0.1 - safe-buffer: ^5.1.2 - checksum: 215d446e43cef021a20b67c1df455e5eea134af0b1f9b8a35f9e850abf32991b0c307327bc5b9bc07162c288d5cdb3d4a783ea6c6640979ed7b5017e3e0c9935 - languageName: node - linkType: hard - -"pull-cat@npm:^1.1.9": - version: 1.1.11 - resolution: "pull-cat@npm:1.1.11" - checksum: 785173d94732ba5e6e65f27ee128542522aeb87519c5d72aa9b8bc510f6c4f67b91fcfd565782a20aafc116e57354f2dd0fa8fd039b45a61b8da89b0253a7440 - languageName: node - linkType: hard - -"pull-defer@npm:^0.2.2": - version: 0.2.3 - resolution: "pull-defer@npm:0.2.3" - checksum: 4ea99ed64a2d79167e87293aba5088cde91f210a319c690a65aa6704d829be33b76cecc732f8d4ed3eee47e7eb09a6f77042897ea6414862bacbd722ce182d66 + "@protobufjs/utf8": ^1.1.0 + "@types/long": ^4.0.1 + "@types/node": ">=13.7.0" + long: ^4.0.0 + bin: + pbjs: bin/pbjs + pbts: bin/pbts + checksum: b2fc6a01897b016c2a7e43a854ab4a3c57080f61be41e552235436e7a730711b8e89e47cb4ae52f0f065b5ab5d5989fc932f390337ce3a8ccf07203415700850 languageName: node linkType: hard -"pull-level@npm:^2.0.3": - version: 2.0.4 - resolution: "pull-level@npm:2.0.4" - dependencies: - level-post: ^1.0.7 - pull-cat: ^1.1.9 - pull-live: ^1.0.1 - pull-pushable: ^2.0.0 - pull-stream: ^3.4.0 - pull-window: ^2.1.4 - stream-to-pull-stream: ^1.7.1 - checksum: f4e0573b3ff3f3659eb50ac86b505aee12d5f4c1d8bafc3bf6fd67d173b3b39a3fe5161d8bfa5eba8a0c5873fbda75f3b160276cfa678d5edd517dcd3349ecc2 +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 languageName: node linkType: hard -"pull-live@npm:^1.0.1": +"prr@npm:~1.0.1": version: 1.0.1 - resolution: "pull-live@npm:1.0.1" - dependencies: - pull-cat: ^1.1.9 - pull-stream: ^3.4.0 - checksum: e4328771e811aec1e03996d1070ec8fecb2560cc48b96814cd9f4aebd870a710903f8693e423765d3d65d8021b3b9ccc38c8660baef3df45e217c9b1bbc5581a - languageName: node - linkType: hard - -"pull-pushable@npm:^2.0.0": - version: 2.2.0 - resolution: "pull-pushable@npm:2.2.0" - checksum: 1c88ef55f6f14799ae5cf060415d089d15452ef865d874f075c155f8224c321371cb7f04a10b3fba263b6f128158c78253efd18bcb54afbb99f9cae846f883a6 - languageName: node - linkType: hard - -"pull-stream@npm:^3.2.3, pull-stream@npm:^3.4.0, pull-stream@npm:^3.6.8": - version: 3.7.0 - resolution: "pull-stream@npm:3.7.0" - checksum: df0b864fd92bb61e84d02764a064bf023188c1c917d854029a5b8e543e163f9aaf1a9553067d4fdf5e248b0d96338e0a23fac9257e86cf740e7d03e05b7a77a3 + resolution: "prr@npm:1.0.1" + checksum: 3bca2db0479fd38f8c4c9439139b0c42dcaadcc2fbb7bb8e0e6afaa1383457f1d19aea9e5f961d5b080f1cfc05bfa1fe9e45c97a1d3fd6d421950a73d3108381 languageName: node linkType: hard -"pull-window@npm:^2.1.4": - version: 2.1.4 - resolution: "pull-window@npm:2.1.4" - dependencies: - looper: ^2.0.0 - checksum: e006995108a80c81eea93dfaadf68285dc5b9b3cbaf654da39731ca3f308376f15b0546c61730cd0fa38303e273a1845c6d65f0fda35ed9c66252a65e446df18 +"psl@npm:^1.1.28": + version: 1.9.0 + resolution: "psl@npm:1.9.0" + checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d languageName: node linkType: hard @@ -13769,13 +9471,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:2.1.0": - version: 2.1.0 - resolution: "punycode@npm:2.1.0" - checksum: d125d8f86cd89303c33bad829388c49ca23197e16ccf8cd398dcbd81b026978f6543f5066c66825b25b1dfea7790a42edbeea82908e103474931789714ab86cd - languageName: node - linkType: hard - "punycode@npm:^1.4.1": version: 1.4.1 resolution: "punycode@npm:1.4.1" @@ -13790,16 +9485,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" - dependencies: - side-channel: ^1.0.4 - checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 - languageName: node - linkType: hard - -"qs@npm:^6.11.2, qs@npm:^6.4.0": +"qs@npm:^6.11.2": version: 6.12.1 resolution: "qs@npm:6.12.1" dependencies: @@ -13815,17 +9501,6 @@ __metadata: languageName: node linkType: hard -"query-string@npm:^5.0.1": - version: 5.1.1 - resolution: "query-string@npm:5.1.1" - dependencies: - decode-uri-component: ^0.2.0 - object-assign: ^4.1.0 - strict-uri-encode: ^1.0.0 - checksum: 4ac760d9778d413ef5f94f030ed14b1a07a1708dd13fd3bc54f8b9ef7b425942c7577f30de0bf5a7d227ee65a9a0350dfa3a43d1d266880882fb7ce4c434a4dd - languageName: node - linkType: hard - "queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -13833,14 +9508,7 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^5.1.1": - version: 5.1.1 - resolution: "quick-lru@npm:5.1.1" - checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed - languageName: node - linkType: hard - -"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.0.6, randombytes@npm:^2.1.0": +"randombytes@npm:^2.0.1, randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" dependencies: @@ -13849,24 +9517,7 @@ __metadata: languageName: node linkType: hard -"randomfill@npm:^1.0.3": - version: 1.0.4 - resolution: "randomfill@npm:1.0.4" - dependencies: - randombytes: ^2.0.5 - safe-buffer: ^5.1.0 - checksum: 33734bb578a868d29ee1b8555e21a36711db084065d94e019a6d03caa67debef8d6a1bfd06a2b597e32901ddc761ab483a85393f0d9a75838f1912461d4dbfc7 - languageName: node - linkType: hard - -"range-parser@npm:~1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 - languageName: node - linkType: hard - -"raw-body@npm:2.5.2, raw-body@npm:^2.4.1": +"raw-body@npm:^2.4.1": version: 2.5.2 resolution: "raw-body@npm:2.5.2" dependencies: @@ -13887,40 +9538,7 @@ __metadata: languageName: node linkType: hard -"read-pkg-up@npm:^1.0.1": - version: 1.0.1 - resolution: "read-pkg-up@npm:1.0.1" - dependencies: - find-up: ^1.0.0 - read-pkg: ^1.0.0 - checksum: d18399a0f46e2da32beb2f041edd0cda49d2f2cc30195a05c759ef3ed9b5e6e19ba1ad1bae2362bdec8c6a9f2c3d18f4d5e8c369e808b03d498d5781cb9122c7 - languageName: node - linkType: hard - -"read-pkg@npm:^1.0.0": - version: 1.1.0 - resolution: "read-pkg@npm:1.1.0" - dependencies: - load-json-file: ^1.0.0 - normalize-package-data: ^2.3.2 - path-type: ^1.0.0 - checksum: a0f5d5e32227ec8e6a028dd5c5134eab229768dcb7a5d9a41a284ed28ad4b9284fecc47383dc1593b5694f4de603a7ffaee84b738956b9b77e0999567485a366 - languageName: node - linkType: hard - -"readable-stream@npm:^1.0.33": - version: 1.1.14 - resolution: "readable-stream@npm:1.1.14" - dependencies: - core-util-is: ~1.0.0 - inherits: ~2.0.1 - isarray: 0.0.1 - string_decoder: ~0.10.x - checksum: 17dfeae3e909945a4a1abc5613ea92d03269ef54c49288599507fc98ff4615988a1c39a999dcf9aacba70233d9b7040bc11a5f2bfc947e262dedcc0a8b32b5a0 - languageName: node - linkType: hard - -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.2.8, readable-stream@npm:^2.2.9, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -13935,7 +9553,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.0, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:^3.1.0, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -13946,7 +9564,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:~1.0.15, readable-stream@npm:~1.0.26-4": +"readable-stream@npm:~1.0.26-4": version: 1.0.34 resolution: "readable-stream@npm:1.0.34" dependencies: @@ -13958,6 +9576,13 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:^4.0.1": + version: 4.0.2 + resolution: "readdirp@npm:4.0.2" + checksum: 309376e717f94fb7eb61bec21e2603243a9e2420cd2e9bf94ddf026aefea0d7377ed1a62f016d33265682e44908049a55c3cfc2307450a1421654ea008489b39 + languageName: node + linkType: hard + "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -14001,42 +9626,7 @@ __metadata: languageName: node linkType: hard -"regenerate@npm:^1.2.1": - version: 1.4.2 - resolution: "regenerate@npm:1.4.2" - checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.11.0": - version: 0.11.1 - resolution: "regenerator-runtime@npm:0.11.1" - checksum: 3c97bd2c7b2b3247e6f8e2147a002eb78c995323732dad5dc70fac8d8d0b758d0295e7015b90d3d444446ae77cbd24b9f9123ec3a77018e81d8999818301b4f4 - languageName: node - linkType: hard - -"regenerator-transform@npm:^0.10.0": - version: 0.10.1 - resolution: "regenerator-transform@npm:0.10.1" - dependencies: - babel-runtime: ^6.18.0 - babel-types: ^6.19.0 - private: ^0.1.6 - checksum: bd366a3b0fa0d0975c48fb9eff250363a9ab28c25b472ecdc397bb19a836746640a30d8f641718a895f9178564bd8a01a0179a9c8e5813f76fc29e62a115d9d7 - languageName: node - linkType: hard - -"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": - version: 1.0.2 - resolution: "regex-not@npm:1.0.2" - dependencies: - extend-shallow: ^3.0.2 - safe-regex: ^1.1.0 - checksum: 3081403de79559387a35ef9d033740e41818a559512668cef3d12da4e8a29ef34ee13c8ed1256b07e27ae392790172e8a15c8a06b72962fd4550476cde3d8f77 - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2": +"regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: @@ -14062,77 +9652,14 @@ __metadata: languageName: node linkType: hard -"regexpu-core@npm:^2.0.0": - version: 2.0.0 - resolution: "regexpu-core@npm:2.0.0" - dependencies: - regenerate: ^1.2.1 - regjsgen: ^0.2.0 - regjsparser: ^0.1.4 - checksum: 14a78eb4608fa991ded6a1433ee6a570f95a4cfb7fe312145a44d6ecbb3dc8c707016a099494c741aa0ac75a1329b40814d30ff134c0d67679c80187029c7d2d - languageName: node - linkType: hard - -"regjsgen@npm:^0.2.0": - version: 0.2.0 - resolution: "regjsgen@npm:0.2.0" - checksum: 1f3ae570151e2c29193cdc5a5890c0b83cd8c5029ed69315b0ea303bc2644f9ab5d536d2288fd9b70293fd351d7dd7fc1fc99ebe24554015c894dbce883bcf2b - languageName: node - linkType: hard - -"regjsparser@npm:^0.1.4": - version: 0.1.5 - resolution: "regjsparser@npm:0.1.5" - dependencies: - jsesc: ~0.5.0 - bin: - regjsparser: bin/parser - checksum: 1feba2f3f2d4f1ef9f5f4e0f20c827cf866d4f65c51502eb64db4d4dd9c656f8c70f6c79537c892bf0fc9592c96f732519f7d8ad4a82f3b622756118ac737970 - languageName: node - linkType: hard - -"repeat-element@npm:^1.1.2": - version: 1.1.4 - resolution: "repeat-element@npm:1.1.4" - checksum: 1edd0301b7edad71808baad226f0890ba709443f03a698224c9ee4f2494c317892dc5211b2ba8cbea7194a9ddbcac01e283bd66de0467ab24ee1fc1a3711d8a9 - languageName: node - linkType: hard - -"repeat-string@npm:^1.0.0, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.0.0": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 languageName: node linkType: hard -"repeating@npm:^2.0.0": - version: 2.0.1 - resolution: "repeating@npm:2.0.1" - dependencies: - is-finite: ^1.0.0 - checksum: d2db0b69c5cb0c14dd750036e0abcd6b3c3f7b2da3ee179786b755cf737ca15fa0fff417ca72de33d6966056f4695440e680a352401fc02c95ade59899afbdd0 - languageName: node - linkType: hard - -"req-cwd@npm:^2.0.0": - version: 2.0.0 - resolution: "req-cwd@npm:2.0.0" - dependencies: - req-from: ^2.0.0 - checksum: c44f9dea0b0f7d3a72be18a04f7769e0eefbadca363e3a346c1c02b79745126c871e1f6970357b3e731c26740aad8344bf80fb3ce055a2bcf8ca85ad2b44f519 - languageName: node - linkType: hard - -"req-from@npm:^2.0.0": - version: 2.0.0 - resolution: "req-from@npm:2.0.0" - dependencies: - resolve-from: ^3.0.0 - checksum: 4c369881a2296e23e71668ed089c5d93b37652fe900ec9f1e1f5c1da65f6bca4ee271e97ba2b806fdea50219e011995d1df3c80a7209015cc1e1fc622507f140 - languageName: node - linkType: hard - -"request@npm:^2.79.0, request@npm:^2.85.0, request@npm:^2.88.0": +"request@npm:^2.85.0, request@npm:^2.88.0": version: 2.88.2 resolution: "request@npm:2.88.2" dependencies: @@ -14167,27 +9694,13 @@ __metadata: languageName: node linkType: hard -"require-from-string@npm:^1.1.0": - version: 1.2.1 - resolution: "require-from-string@npm:1.2.1" - checksum: d2e0b0c798fe45d86456a32425635bd9d2a75a20e87f67294fa5cce5ed61fdf41e0c7c57afa981fb836299bfb0c37c915adb4d22478dc8d12edbf80a304e9324 - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.0, require-from-string@npm:^2.0.2": +"require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b languageName: node linkType: hard -"require-main-filename@npm:^1.0.1": - version: 1.0.1 - resolution: "require-main-filename@npm:1.0.1" - checksum: 1fef30754da961f4e13c450c3eb60c7ae898a529c6ad6fa708a70bd2eed01564ceb299187b2899f5562804d797a059f39a5789884d0ac7b7ae1defc68fba4abf - languageName: node - linkType: hard - "require-main-filename@npm:^2.0.0": version: 2.0.0 resolution: "require-main-filename@npm:2.0.0" @@ -14195,20 +9708,6 @@ __metadata: languageName: node linkType: hard -"resolve-alpn@npm:^1.0.0": - version: 1.2.1 - resolution: "resolve-alpn@npm:1.2.1" - checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 - languageName: node - linkType: hard - -"resolve-from@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-from@npm:3.0.0" - checksum: fff9819254d2d62b57f74e5c2ca9c0bdd425ca47287c4d801bc15f947533148d858229ded7793b0f59e61e49e782fffd6722048add12996e1bd4333c29669062 - languageName: node - linkType: hard - "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -14216,13 +9715,6 @@ __metadata: languageName: node linkType: hard -"resolve-url@npm:^0.2.1": - version: 0.2.1 - resolution: "resolve-url@npm:0.2.1" - checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14 - languageName: node - linkType: hard - "resolve@npm:1.1.x": version: 1.1.7 resolution: "resolve@npm:1.1.7" @@ -14239,7 +9731,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.8.1, resolve@npm:~1.22.6": +"resolve@npm:^1.1.6, resolve@npm:^1.10.1, resolve@npm:^1.22.1, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -14268,7 +9760,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.8.1#~builtin, resolve@patch:resolve@~1.22.6#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=07638b" dependencies: @@ -14281,24 +9773,6 @@ __metadata: languageName: node linkType: hard -"responselike@npm:^1.0.2": - version: 1.0.2 - resolution: "responselike@npm:1.0.2" - dependencies: - lowercase-keys: ^1.0.0 - checksum: 2e9e70f1dcca3da621a80ce71f2f9a9cad12c047145c6ece20df22f0743f051cf7c73505e109814915f23f9e34fb0d358e22827723ee3d56b623533cab8eafcd - languageName: node - linkType: hard - -"responselike@npm:^2.0.0": - version: 2.0.1 - resolution: "responselike@npm:2.0.1" - dependencies: - lowercase-keys: ^2.0.0 - checksum: b122535466e9c97b55e69c7f18e2be0ce3823c5d47ee8de0d9c0b114aa55741c6db8bfbfce3766a94d1272e61bfb1ebf0a15e9310ac5629fbb7446a861b4fd3a - languageName: node - linkType: hard - "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -14309,13 +9783,6 @@ __metadata: languageName: node linkType: hard -"ret@npm:~0.1.10": - version: 0.1.15 - resolution: "ret@npm:0.1.15" - checksum: d76a9159eb8c946586567bd934358dfc08a36367b3257f7a3d7255fdd7b56597235af23c6afa0d7f0254159e8051f93c918809962ebd6df24ca2a83dbe4d4151 - languageName: node - linkType: hard - "retimer@npm:^3.0.0": version: 3.0.0 resolution: "retimer@npm:3.0.0" @@ -14355,7 +9822,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^2.2.8, rimraf@npm:^2.6.3": +"rimraf@npm:^2.6.3": version: 2.7.1 resolution: "rimraf@npm:2.7.1" dependencies: @@ -14398,7 +9865,7 @@ __metadata: languageName: node linkType: hard -"rlp@npm:^2.0.0, rlp@npm:^2.2.1, rlp@npm:^2.2.2, rlp@npm:^2.2.3, rlp@npm:^2.2.4": +"rlp@npm:^2.2.3, rlp@npm:^2.2.4": version: 2.2.7 resolution: "rlp@npm:2.2.7" dependencies: @@ -14441,16 +9908,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.2.0": - version: 7.8.1 - resolution: "rxjs@npm:7.8.1" - dependencies: - tslib: ^2.1.0 - checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119 - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.0.0, safe-array-concat@npm:^1.1.2": +"safe-array-concat@npm:^1.1.2": version: 1.1.2 resolution: "safe-array-concat@npm:1.1.2" dependencies: @@ -14462,7 +9920,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -14476,15 +9934,6 @@ __metadata: languageName: node linkType: hard -"safe-event-emitter@npm:^1.0.1": - version: 1.0.1 - resolution: "safe-event-emitter@npm:1.0.1" - dependencies: - events: ^3.0.0 - checksum: 2a15094bd28b0966571693f219b5a846949ae24f7ba87c6024f0ed552bef63ebe72970a784b85b77b1f03f1c95e78fabe19306d44538dbc4a3a685bed31c18c4 - languageName: node - linkType: hard - "safe-regex-test@npm:^1.0.3": version: 1.0.3 resolution: "safe-regex-test@npm:1.0.3" @@ -14496,15 +9945,6 @@ __metadata: languageName: node linkType: hard -"safe-regex@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex@npm:1.1.0" - dependencies: - ret: ~0.1.10 - checksum: 9a8bba57c87a841f7997b3b951e8e403b1128c1a4fd1182f40cc1a20e2d490593d7c2a21030fadfea320c8e859219019e136f678c6689ed5960b391b822f01d5 - languageName: node - linkType: hard - "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -14536,22 +9976,13 @@ __metadata: languageName: node linkType: hard -"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": +"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" checksum: b7c7d1a68d6ca946f2fbb0778e0c4ec63c65501b54023b2af7d7e9f48fdb6c6580d6f7675cd53bda5944c5ebc057560d5a6365079752546865defb3b79dea454 languageName: node linkType: hard -"scryptsy@npm:^1.2.1": - version: 1.2.1 - resolution: "scryptsy@npm:1.2.1" - dependencies: - pbkdf2: ^3.0.3 - checksum: e09cf253b0974171bbcb77fa46405bb07cb8e241e2851fc5f23b38526a33105f0f7748a4d60027642f40bd4518ada30b1dce5005c05d17a25cbcefad371d4259 - languageName: node - linkType: hard - "secp256k1@npm:4.0.3, secp256k1@npm:^4.0.1": version: 4.0.3 resolution: "secp256k1@npm:4.0.3" @@ -14564,13 +9995,6 @@ __metadata: languageName: node linkType: hard -"seedrandom@npm:3.0.1": - version: 3.0.1 - resolution: "seedrandom@npm:3.0.1" - checksum: a8f5bd0e918c4d4b59afd6f5dbd28f5ab8d5f118ee59892c3712f581de51574ac6622aa38fa2d03476b661f8407e98d6ff32af3d7cfdb02c90d046e7f5f91952 - languageName: node - linkType: hard - "seedrandom@npm:3.0.5": version: 3.0.5 resolution: "seedrandom@npm:3.0.5" @@ -14585,14 +10009,7 @@ __metadata: languageName: node linkType: hard -"semaphore@npm:>=1.0.1, semaphore@npm:^1.0.3, semaphore@npm:^1.1.0": - version: 1.1.0 - resolution: "semaphore@npm:1.1.0" - checksum: d2445d232ad9959048d4748ef54eb01bc7b60436be2b42fb7de20c4cffacf70eafeeecd3772c1baf408cfdce3805fa6618a4389590335671f18cde54ef3cfae4 - languageName: node - linkType: hard - -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.3.0, semver@npm:^5.5.0, semver@npm:^5.6.0": +"semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" bin: @@ -14619,36 +10036,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:~5.4.1": - version: 5.4.1 - resolution: "semver@npm:5.4.1" - bin: - semver: ./bin/semver - checksum: d4bf8cc6a95b065a545ab35082b6ac6c5f4ebe1e1c570f72c252afe9b7e622f2479fb2a5cef3e937d8807d37bfdad2d1feebcc8610e06f556e552c22cad070a2 - languageName: node - linkType: hard - -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - etag: ~1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: ~1.2.1 - statuses: 2.0.1 - checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 - languageName: node - linkType: hard - "serialize-javascript@npm:6.0.0": version: 6.0.0 resolution: "serialize-javascript@npm:6.0.0" @@ -14658,31 +10045,6 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" - dependencies: - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - parseurl: ~1.3.3 - send: 0.18.0 - checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d - languageName: node - linkType: hard - -"servify@npm:^0.1.12": - version: 0.1.12 - resolution: "servify@npm:0.1.12" - dependencies: - body-parser: ^1.16.0 - cors: ^2.8.1 - express: ^4.14.0 - request: ^2.79.0 - xhr: ^2.3.3 - checksum: f90e8f4e31b2981b31e3fa8be0b570b0876136b4cf818ba3bfb65e1bfb3c54cb90a0c30898a7c2974b586800bd26ff525c838a8c170148d9e6674c2170f535d8 - languageName: node - linkType: hard - "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" @@ -14716,25 +10078,6 @@ __metadata: languageName: node linkType: hard -"set-immediate-shim@npm:^1.0.1": - version: 1.0.1 - resolution: "set-immediate-shim@npm:1.0.1" - checksum: 5085c84039d1e5eee73d2bf48ce765fcec76159021d0cc7b40e23bcdf62cb6d450ffb781e3c62c1118425242c48eae96df712cba0a20a437e86b0d4a15d51a11 - languageName: node - linkType: hard - -"set-value@npm:^2.0.0, set-value@npm:^2.0.1": - version: 2.0.1 - resolution: "set-value@npm:2.0.1" - dependencies: - extend-shallow: ^2.0.1 - is-extendable: ^0.1.1 - is-plain-object: ^2.0.3 - split-string: ^3.0.1 - checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601 - languageName: node - linkType: hard - "setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" @@ -14842,38 +10185,6 @@ __metadata: languageName: node linkType: hard -"simple-concat@npm:^1.0.0": - version: 1.0.1 - resolution: "simple-concat@npm:1.0.1" - checksum: 4d211042cc3d73a718c21ac6c4e7d7a0363e184be6a5ad25c8a1502e49df6d0a0253979e3d50dbdd3f60ef6c6c58d756b5d66ac1e05cda9cacd2e9fc59e3876a - languageName: node - linkType: hard - -"simple-get@npm:^2.7.0": - version: 2.8.2 - resolution: "simple-get@npm:2.8.2" - dependencies: - decompress-response: ^3.3.0 - once: ^1.3.1 - simple-concat: ^1.0.0 - checksum: 230bd931d3198f21a5a1a566687a5ee1ef651b13b61c7a01b547b2a0c2bf72769b5fe14a3b4dd518e99a18ba1002ba8af3901c0e61e8a0d1e7631a3c2eb1f7a9 - languageName: node - linkType: hard - -"slash@npm:^1.0.0": - version: 1.0.0 - resolution: "slash@npm:1.0.0" - checksum: 4b6e21b1fba6184a7e2efb1dd173f692d8a845584c1bbf9dc818ff86f5a52fc91b413008223d17cc684604ee8bb9263a420b1182027ad9762e35388434918860 - languageName: node - linkType: hard - -"slash@npm:^2.0.0": - version: 2.0.0 - resolution: "slash@npm:2.0.0" - checksum: 512d4350735375bd11647233cb0e2f93beca6f53441015eea241fe784d8068281c3987fbaa93e7ef1c38df68d9c60013045c92837423c69115297d6169aa85e6 - languageName: node - linkType: hard - "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -14899,50 +10210,14 @@ __metadata: ansi-styles: ^4.0.0 astral-regex: ^2.0.0 is-fullwidth-code-point: ^3.0.0 - checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b - languageName: node - linkType: hard - -"snapdragon-node@npm:^2.0.1": - version: 2.1.1 - resolution: "snapdragon-node@npm:2.1.1" - dependencies: - define-property: ^1.0.0 - isobject: ^3.0.0 - snapdragon-util: ^3.0.1 - checksum: 9bb57d759f9e2a27935dbab0e4a790137adebace832b393e350a8bf5db461ee9206bb642d4fe47568ee0b44080479c8b4a9ad0ebe3712422d77edf9992a672fd - languageName: node - linkType: hard - -"snapdragon-util@npm:^3.0.1": - version: 3.0.1 - resolution: "snapdragon-util@npm:3.0.1" - dependencies: - kind-of: ^3.2.0 - checksum: 684997dbe37ec995c03fd3f412fba2b711fc34cb4010452b7eb668be72e8811a86a12938b511e8b19baf853b325178c56d8b78d655305e5cfb0bb8b21677e7b7 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 languageName: node linkType: hard -"snapdragon@npm:^0.8.1": - version: 0.8.2 - resolution: "snapdragon@npm:0.8.2" - dependencies: - base: ^0.11.1 - debug: ^2.2.0 - define-property: ^0.2.5 - extend-shallow: ^2.0.1 - map-cache: ^0.2.2 - source-map: ^0.5.6 - source-map-resolve: ^0.5.0 - use: ^3.1.0 - checksum: a197f242a8f48b11036563065b2487e9b7068f50a20dd81d9161eca6af422174fc158b8beeadbe59ce5ef172aa5718143312b3aebaae551c124b7824387c8312 +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b languageName: node linkType: hard @@ -14967,25 +10242,6 @@ __metadata: languageName: node linkType: hard -"solc@npm:0.7.3": - version: 0.7.3 - resolution: "solc@npm:0.7.3" - dependencies: - command-exists: ^1.2.8 - commander: 3.0.2 - follow-redirects: ^1.12.1 - fs-extra: ^0.30.0 - js-sha3: 0.8.0 - memorystream: ^0.3.1 - require-from-string: ^2.0.0 - semver: ^5.5.0 - tmp: 0.0.33 - bin: - solcjs: solcjs - checksum: 2d8eb16c6d8f648213c94dc8d977cffe5099cba7d41c82d92d769ef71ae8320a985065ce3d6c306440a85f8e8d2b27fb30bdd3ac38f69e5c1fa0ab8a3fb2f217 - languageName: node - linkType: hard - "solc@npm:0.8.15": version: 0.8.15 resolution: "solc@npm:0.8.15" @@ -15020,39 +10276,6 @@ __metadata: languageName: node linkType: hard -"solc@npm:^0.4.20": - version: 0.4.26 - resolution: "solc@npm:0.4.26" - dependencies: - fs-extra: ^0.30.0 - memorystream: ^0.3.1 - require-from-string: ^1.1.0 - semver: ^5.3.0 - yargs: ^4.7.1 - bin: - solcjs: solcjs - checksum: 041da7ff725c19023ef34a17f83b3303971d2e62bcea9d0fd3c7af728d6f40ff7cdf2b806d0208a3336d3c9be18c321955e1712ab39ee57390ba00d512def946 - languageName: node - linkType: hard - -"solc@npm:^0.6.3": - version: 0.6.12 - resolution: "solc@npm:0.6.12" - dependencies: - command-exists: ^1.2.8 - commander: 3.0.2 - fs-extra: ^0.30.0 - js-sha3: 0.8.0 - memorystream: ^0.3.1 - require-from-string: ^2.0.0 - semver: ^5.5.0 - tmp: 0.0.33 - bin: - solcjs: solcjs - checksum: 1e2bf927f3ef4f3b195b7619ff64f715916d94dc59091a8a710e47bdd4b18e0bd92b55ea43a04ce7fabce9ad7a3e4e73ccaf127a50ebbf963a9de9046576e3b6 - languageName: node - linkType: hard - "solhint@npm:^3.3.7": version: 3.6.2 resolution: "solhint@npm:3.6.2" @@ -15131,19 +10354,6 @@ __metadata: languageName: node linkType: hard -"source-map-resolve@npm:^0.5.0": - version: 0.5.3 - resolution: "source-map-resolve@npm:0.5.3" - dependencies: - atob: ^2.1.2 - decode-uri-component: ^0.2.0 - resolve-url: ^0.2.1 - source-map-url: ^0.4.0 - urix: ^0.1.0 - checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae - languageName: node - linkType: hard - "source-map-support@npm:0.5.12": version: 0.5.12 resolution: "source-map-support@npm:0.5.12" @@ -15154,15 +10364,6 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.4.15": - version: 0.4.18 - resolution: "source-map-support@npm:0.4.18" - dependencies: - source-map: ^0.5.6 - checksum: 669aa7e992fec586fac0ba9a8dea8ce81b7328f92806335f018ffac5709afb2920e3870b4e56c68164282607229f04b8bbcf5d0e5c845eb1b5119b092e7585c0 - languageName: node - linkType: hard - "source-map-support@npm:^0.5.11, source-map-support@npm:^0.5.13, source-map-support@npm:^0.5.16": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" @@ -15173,20 +10374,6 @@ __metadata: languageName: node linkType: hard -"source-map-url@npm:^0.4.0": - version: 0.4.1 - resolution: "source-map-url@npm:0.4.1" - checksum: 64c5c2c77aff815a6e61a4120c309ae4cac01298d9bcbb3deb1b46a4dd4c46d4a1eaeda79ec9f684766ae80e8dc86367b89326ce9dd2b89947bd9291fc1ac08c - languageName: node - linkType: hard - -"source-map@npm:^0.5.6, source-map@npm:^0.5.7": - version: 0.5.7 - resolution: "source-map@npm:0.5.7" - checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d - languageName: node - linkType: hard - "source-map@npm:^0.6.0, source-map@npm:^0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" @@ -15203,40 +10390,6 @@ __metadata: languageName: node linkType: hard -"spdx-correct@npm:^3.0.0": - version: 3.2.0 - resolution: "spdx-correct@npm:3.2.0" - dependencies: - spdx-expression-parse: ^3.0.0 - spdx-license-ids: ^3.0.0 - checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 - languageName: node - linkType: hard - -"spdx-exceptions@npm:^2.1.0": - version: 2.5.0 - resolution: "spdx-exceptions@npm:2.5.0" - checksum: bb127d6e2532de65b912f7c99fc66097cdea7d64c10d3ec9b5e96524dbbd7d20e01cba818a6ddb2ae75e62bb0c63d5e277a7e555a85cbc8ab40044984fa4ae15 - languageName: node - linkType: hard - -"spdx-expression-parse@npm:^3.0.0": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: ^2.1.0 - spdx-license-ids: ^3.0.0 - checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde - languageName: node - linkType: hard - -"spdx-license-ids@npm:^3.0.0": - version: 3.0.18 - resolution: "spdx-license-ids@npm:3.0.18" - checksum: 457825df5dd1fc0135b0bb848c896143f70945cc2da148afc71c73ed0837d1d651f809006e406d82109c9dd71a8cb39785a3604815fe46bc0548e9d3976f6b69 - languageName: node - linkType: hard - "split-ca@npm:^1.0.0": version: 1.0.1 resolution: "split-ca@npm:1.0.1" @@ -15244,15 +10397,6 @@ __metadata: languageName: node linkType: hard -"split-string@npm:^3.0.1, split-string@npm:^3.0.2": - version: 3.1.0 - resolution: "split-string@npm:3.1.0" - dependencies: - extend-shallow: ^3.0.0 - checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c - languageName: node - linkType: hard - "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -15306,16 +10450,6 @@ __metadata: languageName: node linkType: hard -"static-extend@npm:^0.1.1": - version: 0.1.2 - resolution: "static-extend@npm:0.1.2" - dependencies: - define-property: ^0.2.5 - object-copy: ^0.1.0 - checksum: 8657485b831f79e388a437260baf22784540417a9b29e11572c87735df24c22b84eda42107403a64b30861b2faf13df9f7fc5525d51f9d1d2303aba5cbf4e12c - languageName: node - linkType: hard - "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -15332,23 +10466,6 @@ __metadata: languageName: node linkType: hard -"stream-to-pull-stream@npm:^1.7.1": - version: 1.7.3 - resolution: "stream-to-pull-stream@npm:1.7.3" - dependencies: - looper: ^3.0.0 - pull-stream: ^3.2.3 - checksum: 2b878e3b3d5f435802866bfec8897361b9de4ce69f77669da1103cfc45f54833e7c183922468f30c046d375a1642f5a4801a808a8da0d3927c5de41d42a59bc0 - languageName: node - linkType: hard - -"strict-uri-encode@npm:^1.0.0": - version: 1.1.0 - resolution: "strict-uri-encode@npm:1.1.0" - checksum: 9466d371f7b36768d43f7803f26137657559e4c8b0161fb9e320efb8edba3ae22f8e99d4b0d91da023b05a13f62ec5412c3f4f764b5788fac11d1fea93720bb3 - languageName: node - linkType: hard - "string-format@npm:^2.0.0": version: 2.0.0 resolution: "string-format@npm:2.0.0" @@ -15367,17 +10484,6 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^1.0.1": - version: 1.0.2 - resolution: "string-width@npm:1.0.2" - dependencies: - code-point-at: ^1.0.0 - is-fullwidth-code-point: ^1.0.0 - strip-ansi: ^3.0.0 - checksum: 5c79439e95bc3bd7233a332c5f5926ab2ee90b23816ed4faa380ce3b2576d7800b0a5bb15ae88ed28737acc7ea06a518c2eef39142dd727adad0e45c776cd37e - languageName: node - linkType: hard - "string-width@npm:^2.1.1": version: 2.1.1 resolution: "string-width@npm:2.1.1" @@ -15410,7 +10516,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.9, string.prototype.trim@npm:~1.2.8": +"string.prototype.trim@npm:^1.2.9": version: 1.2.9 resolution: "string.prototype.trim@npm:1.2.9" dependencies: @@ -15478,15 +10584,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1": - version: 3.0.1 - resolution: "strip-ansi@npm:3.0.1" - dependencies: - ansi-regex: ^2.0.0 - checksum: 9b974de611ce5075c70629c00fa98c46144043db92ae17748fb780f706f7a789e9989fd10597b7c2053ae8d1513fd707816a91f1879b2f71e6ac0b6a863db465 - languageName: node - linkType: hard - "strip-ansi@npm:^4.0.0": version: 4.0.0 resolution: "strip-ansi@npm:4.0.0" @@ -15514,15 +10611,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-bom@npm:2.0.0" - dependencies: - is-utf8: ^0.2.0 - checksum: 08efb746bc67b10814cd03d79eb31bac633393a782e3f35efbc1b61b5165d3806d03332a97f362822cf0d4dd14ba2e12707fcff44fe1c870c48a063a0c9e4944 - languageName: node - linkType: hard - "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -15569,13 +10657,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^2.0.0": - version: 2.0.0 - resolution: "supports-color@npm:2.0.0" - checksum: 602538c5812b9006404370b5a4b885d3e2a1f6567d314f8b4a41974ffe7d08e525bf92ae0f9c7030e3b4c78e4e34ace55d6a67a74f1571bc205959f5972f88f0 - languageName: node - linkType: hard - "supports-color@npm:^3.1.0": version: 3.2.3 resolution: "supports-color@npm:3.2.3" @@ -15610,45 +10691,6 @@ __metadata: languageName: node linkType: hard -"swarm-js@npm:^0.1.40": - version: 0.1.42 - resolution: "swarm-js@npm:0.1.42" - dependencies: - bluebird: ^3.5.0 - buffer: ^5.0.5 - eth-lib: ^0.1.26 - fs-extra: ^4.0.2 - got: ^11.8.5 - mime-types: ^2.1.16 - mkdirp-promise: ^5.0.1 - mock-fs: ^4.1.0 - setimmediate: ^1.0.5 - tar: ^4.0.2 - xhr-request: ^1.0.1 - checksum: bbb54b84232ef113ee106cf8158d1c827fbf84b309799576f61603f63d7653fde7e71df981d07f9e4c41781bbbbd72be77e5a47e6b694d6a83b96a6a20641475 - languageName: node - linkType: hard - -"sync-request@npm:^6.0.0": - version: 6.1.0 - resolution: "sync-request@npm:6.1.0" - dependencies: - http-response-object: ^3.0.1 - sync-rpc: ^1.2.1 - then-request: ^6.0.0 - checksum: cc8438a6749f62fb501d022fae0e3af3ac4a9983f889f929c8721b328a1c3408b98ca218aad886785a02be2c34bd75eb1a5a2608bd1fcee3c8c099391ff53a11 - languageName: node - linkType: hard - -"sync-rpc@npm:^1.2.1": - version: 1.3.6 - resolution: "sync-rpc@npm:1.3.6" - dependencies: - get-port: ^3.1.0 - checksum: 4340974fb5641c2cadb9df18d6b791ed2327f28cf6d8a00c99ebc2278e37391e3f5e237596da2ff83d14d2147594c6f5b3b98a93b9327644db425d239dea172f - languageName: node - linkType: hard - "table-layout@npm:^1.0.2": version: 1.0.2 resolution: "table-layout@npm:1.0.2" @@ -15686,32 +10728,6 @@ __metadata: languageName: node linkType: hard -"tape@npm:^4.6.3": - version: 4.17.0 - resolution: "tape@npm:4.17.0" - dependencies: - "@ljharb/resumer": ~0.0.1 - "@ljharb/through": ~2.3.9 - call-bind: ~1.0.2 - deep-equal: ~1.1.1 - defined: ~1.0.1 - dotignore: ~0.1.2 - for-each: ~0.3.3 - glob: ~7.2.3 - has: ~1.0.3 - inherits: ~2.0.4 - is-regex: ~1.1.4 - minimist: ~1.2.8 - mock-property: ~1.0.0 - object-inspect: ~1.12.3 - resolve: ~1.22.6 - string.prototype.trim: ~1.2.8 - bin: - tape: bin/tape - checksum: b785f4997f4323d9a1b6f5bda97aaea65a4c68f81296ab46bd126776f3c6f4203073187d5a4bcaa98884bf28e3cfaa50c2d8d81cc0025e4777054455837390dc - languageName: node - linkType: hard - "tar-fs@npm:~1.16.3": version: 1.16.3 resolution: "tar-fs@npm:1.16.3" @@ -15739,21 +10755,6 @@ __metadata: languageName: node linkType: hard -"tar@npm:^4.0.2": - version: 4.4.19 - resolution: "tar@npm:4.4.19" - dependencies: - chownr: ^1.1.4 - fs-minipass: ^1.2.7 - minipass: ^2.9.0 - minizlib: ^1.3.3 - mkdirp: ^0.5.5 - safe-buffer: ^5.2.1 - yallist: ^3.1.1 - checksum: 423c8259b17f8f612cef9c96805d65f90ba9a28e19be582cd9d0fcb217038219f29b7547198e8fd617da5f436376d6a74b99827acd1238d2f49cf62330f9664e - languageName: node - linkType: hard - "tar@npm:^6.1.11, tar@npm:^6.1.2": version: 6.2.1 resolution: "tar@npm:6.2.1" @@ -15768,23 +10769,6 @@ __metadata: languageName: node linkType: hard -"test-value@npm:^2.1.0": - version: 2.1.0 - resolution: "test-value@npm:2.1.0" - dependencies: - array-back: ^1.0.3 - typical: ^2.6.0 - checksum: ce41ef4100c9ac84630e78d1ca06706714587faf255e44296ace1fc7bf5b888c160b8c0229d31467252a3b2b57197965194391f6ee0c54f33e0b8e3af3a33a0c - languageName: node - linkType: hard - -"testrpc@npm:0.0.1": - version: 0.0.1 - resolution: "testrpc@npm:0.0.1" - checksum: e27778552df2d0b938b062fdf41d44557f0eb3de75903cb90b87909f55a82a6345dd13e40d1498e718272b4e5225872dca66da73646c35df1031486bb0ed0fda - languageName: node - linkType: hard - "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -15792,35 +10776,6 @@ __metadata: languageName: node linkType: hard -"then-request@npm:^6.0.0": - version: 6.0.2 - resolution: "then-request@npm:6.0.2" - dependencies: - "@types/concat-stream": ^1.6.0 - "@types/form-data": 0.0.33 - "@types/node": ^8.0.0 - "@types/qs": ^6.2.31 - caseless: ~0.12.0 - concat-stream: ^1.6.0 - form-data: ^2.2.0 - http-basic: ^8.1.1 - http-response-object: ^3.0.1 - promise: ^8.0.0 - qs: ^6.4.0 - checksum: a24a4fc95dd8591966bf3752f024f5cd4d53c2b2c29b23b4e40c3322df6a432d939bc17b589d8e9d760b90e92ab860f6f361a4dfcfe3542019e1615fb51afccc - languageName: node - linkType: hard - -"through2@npm:^2.0.3": - version: 2.0.5 - resolution: "through2@npm:2.0.5" - dependencies: - readable-stream: ~2.3.6 - xtend: ~4.0.1 - checksum: beb0f338aa2931e5660ec7bf3ad949e6d2e068c31f4737b9525e5201b824ac40cac6a337224856b56bd1ddd866334bbfb92a9f57cd6f66bc3f18d3d86fc0fe50 - languageName: node - linkType: hard - "through@npm:>=2.2.7 <3, through@npm:^2.3.6": version: 2.3.8 resolution: "through@npm:2.3.8" @@ -15828,13 +10783,6 @@ __metadata: languageName: node linkType: hard -"timed-out@npm:^4.0.1": - version: 4.0.1 - resolution: "timed-out@npm:4.0.1" - checksum: 98efc5d6fc0d2a329277bd4d34f65c1bf44d9ca2b14fd267495df92898f522e6f563c5e9e467c418e0836f5ca1f47a84ca3ee1de79b1cc6fe433834b7f02ec54 - languageName: node - linkType: hard - "timeout-abort-controller@npm:^2.0.0": version: 2.0.0 resolution: "timeout-abort-controller@npm:2.0.0" @@ -15846,6 +10794,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.6": + version: 0.2.10 + resolution: "tinyglobby@npm:0.2.10" + dependencies: + fdir: ^6.4.2 + picomatch: ^4.0.2 + checksum: 7e2ffe262ebc149036bdef37c56b32d02d52cf09efa7d43dbdab2ea3c12844a4da881058835ce4c74d1891190e5ad5ec5133560a11ec8314849b68ad0d99d3f4 + languageName: node + linkType: hard + "tmp-promise@npm:^3.0.2": version: 3.0.3 resolution: "tmp-promise@npm:3.0.3" @@ -15864,15 +10822,6 @@ __metadata: languageName: node linkType: hard -"tmp@npm:0.1.0": - version: 0.1.0 - resolution: "tmp@npm:0.1.0" - dependencies: - rimraf: ^2.6.3 - checksum: 6bab8431de9d245d4264bd8cd6bb216f9d22f179f935dada92a11d1315572c8eb7c3334201e00594b4708608bd536fad3a63bfb037e7804d827d66aa53a1afcd - languageName: node - linkType: hard - "tmp@npm:^0.2.0": version: 0.2.3 resolution: "tmp@npm:0.2.3" @@ -15887,39 +10836,6 @@ __metadata: languageName: node linkType: hard -"to-fast-properties@npm:^1.0.3": - version: 1.0.3 - resolution: "to-fast-properties@npm:1.0.3" - checksum: bd0abb58c4722851df63419de3f6d901d5118f0440d3f71293ed776dd363f2657edaaf2dc470e3f6b7b48eb84aa411193b60db8a4a552adac30de9516c5cc580 - languageName: node - linkType: hard - -"to-object-path@npm:^0.3.0": - version: 0.3.0 - resolution: "to-object-path@npm:0.3.0" - dependencies: - kind-of: ^3.0.2 - checksum: 9425effee5b43e61d720940fa2b889623f77473d459c2ce3d4a580a4405df4403eec7be6b857455908070566352f9e2417304641ed158dda6f6a365fe3e66d70 - languageName: node - linkType: hard - -"to-readable-stream@npm:^1.0.0": - version: 1.0.0 - resolution: "to-readable-stream@npm:1.0.0" - checksum: 2bd7778490b6214a2c40276065dd88949f4cf7037ce3964c76838b8cb212893aeb9cceaaf4352a4c486e3336214c350270f3263e1ce7a0c38863a715a4d9aeb5 - languageName: node - linkType: hard - -"to-regex-range@npm:^2.1.0": - version: 2.1.1 - resolution: "to-regex-range@npm:2.1.1" - dependencies: - is-number: ^3.0.0 - repeat-string: ^1.6.1 - checksum: 46093cc14be2da905cc931e442d280b2e544e2bfdb9a24b3cf821be8d342f804785e5736c108d5be026021a05d7b38144980a61917eee3c88de0a5e710e10320 - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -15929,18 +10845,6 @@ __metadata: languageName: node linkType: hard -"to-regex@npm:^3.0.1, to-regex@npm:^3.0.2": - version: 3.0.2 - resolution: "to-regex@npm:3.0.2" - dependencies: - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - regex-not: ^1.0.2 - safe-regex: ^1.1.0 - checksum: 4ed4a619059b64e204aad84e4e5f3ea82d97410988bcece7cf6cbfdbf193d11bff48cf53842d88b8bb00b1bfc0d048f61f20f0709e6f393fd8fe0122662d9db4 - languageName: node - linkType: hard - "toidentifier@npm:1.0.1": version: 1.0.1 resolution: "toidentifier@npm:1.0.1" @@ -15978,13 +10882,6 @@ __metadata: languageName: node linkType: hard -"trim-right@npm:^1.0.1": - version: 1.0.1 - resolution: "trim-right@npm:1.0.1" - checksum: 9120af534e006a7424a4f9358710e6e707887b6ccf7ea69e50d6ac6464db1fe22268400def01752f09769025d480395159778153fb98d4a2f6f40d4cf5d4f3b6 - languageName: node - linkType: hard - "ts-command-line-args@npm:^2.2.0": version: 2.5.1 resolution: "ts-command-line-args@npm:2.5.1" @@ -15999,22 +10896,6 @@ __metadata: languageName: node linkType: hard -"ts-essentials@npm:^1.0.0": - version: 1.0.4 - resolution: "ts-essentials@npm:1.0.4" - checksum: 2e19bbe51203707ca732dcc6c3f238b2cf22bb9213d26ae0246c02325fb3e5f17c32505ac79c1bd538b7951a798155b07422e263a95cb295070a48233e45a1b5 - languageName: node - linkType: hard - -"ts-essentials@npm:^6.0.3": - version: 6.0.7 - resolution: "ts-essentials@npm:6.0.7" - peerDependencies: - typescript: ">=3.7.0" - checksum: b47a1793df9ea997d50d2cc9155433952b189cfca0c534a6f3f3dce6aa782a37574d2179dee6d55ed918835aa17addda49619ff2bd2eb3e60e331db3ce30a79b - languageName: node - linkType: hard - "ts-essentials@npm:^7.0.1": version: 7.0.3 resolution: "ts-essentials@npm:7.0.3" @@ -16024,25 +10905,6 @@ __metadata: languageName: node linkType: hard -"ts-generator@npm:^0.1.1": - version: 0.1.1 - resolution: "ts-generator@npm:0.1.1" - dependencies: - "@types/mkdirp": ^0.5.2 - "@types/prettier": ^2.1.1 - "@types/resolve": ^0.0.8 - chalk: ^2.4.1 - glob: ^7.1.2 - mkdirp: ^0.5.1 - prettier: ^2.1.2 - resolve: ^1.8.1 - ts-essentials: ^1.0.0 - bin: - ts-generator: dist/cli/run.js - checksum: 3add2e76afd7a4d9d9aee1ff26477ee4e8b4cc740b35787f9ea780c11aefc88e6c7833837eacc12b944c1883680639dc9cc47fe173eff95c62112f3a41132146 - languageName: node - linkType: hard - "ts-node@npm:^10.9.1": version: 10.9.2 resolution: "ts-node@npm:10.9.2" @@ -16107,7 +10969,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.6.2": +"tslib@npm:^2.3.1, tslib@npm:^2.6.2": version: 2.6.3 resolution: "tslib@npm:2.6.3" checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5 @@ -16141,7 +11003,7 @@ __metadata: languageName: node linkType: hard -"tweetnacl-util@npm:^0.15.0, tweetnacl-util@npm:^0.15.1": +"tweetnacl-util@npm:^0.15.1": version: 0.15.1 resolution: "tweetnacl-util@npm:0.15.1" checksum: ae6aa8a52cdd21a95103a4cc10657d6a2040b36c7a6da7b9d3ab811c6750a2d5db77e8c36969e75fdee11f511aa2b91c552496c6e8e989b6e490e54aca2864fc @@ -16155,7 +11017,7 @@ __metadata: languageName: node linkType: hard -"tweetnacl@npm:^1.0.0, tweetnacl@npm:^1.0.3": +"tweetnacl@npm:^1.0.3": version: 1.0.3 resolution: "tweetnacl@npm:1.0.3" checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c @@ -16215,40 +11077,6 @@ __metadata: languageName: node linkType: hard -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: 0.3.0 - mime-types: ~2.1.24 - checksum: 2c8e47675d55f8b4e404bcf529abdf5036c537a04c2b20177bcf78c9e3c1da69da3942b1346e6edb09e823228c0ee656ef0e033765ec39a70d496ef601a0c657 - languageName: node - linkType: hard - -"type@npm:^2.7.2": - version: 2.7.3 - resolution: "type@npm:2.7.3" - checksum: 69cfda3248847998f93b9d292fd251c10facf8d29513e2047d4684509d67bae82d910d7a00c1e9d9bbf2af242d36425b6616807d6c652c5c370c2be1f0008a47 - languageName: node - linkType: hard - -"typechain@npm:^3.0.0": - version: 3.0.0 - resolution: "typechain@npm:3.0.0" - dependencies: - command-line-args: ^4.0.7 - debug: ^4.1.1 - fs-extra: ^7.0.0 - js-sha3: ^0.8.0 - lodash: ^4.17.15 - ts-essentials: ^6.0.3 - ts-generator: ^0.1.1 - bin: - typechain: ./dist/cli/cli.js - checksum: a38aff5e89c41e20e2c3a1f7b5f04666dbc94b5592eba70ba7d1e0aeb49089d22ed3d35e55a0b0d1f0bfdcea9818157fa4ee3854ef818f46f6aa899520fe7c25 - languageName: node - linkType: hard - "typechain@npm:^8.0.0, typechain@npm:^8.1.0": version: 8.3.2 resolution: "typechain@npm:8.3.2" @@ -16323,15 +11151,6 @@ __metadata: languageName: node linkType: hard -"typedarray-to-buffer@npm:^3.1.5": - version: 3.1.5 - resolution: "typedarray-to-buffer@npm:3.1.5" - dependencies: - is-typedarray: ^1.0.0 - checksum: 99c11aaa8f45189fcfba6b8a4825fd684a321caa9bd7a76a27cf0c7732c174d198b99f449c52c3818107430b5f41c0ccbbfb75cb2ee3ca4a9451710986d61a60 - languageName: node - linkType: hard - "typedarray@npm:^0.0.6": version: 0.0.6 resolution: "typedarray@npm:0.0.6" @@ -16361,51 +11180,21 @@ __metadata: "typescript@patch:typescript@^3.5.2#~builtin": version: 3.9.10 - resolution: "typescript@patch:typescript@npm%3A3.9.10#~builtin::version=3.9.10&hash=7ad353" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: dc7141ab555b23a8650a6787f98845fc11692063d02b75ff49433091b3af2fe3d773650dea18389d7c21f47d620fb3b110ea363dab4ab039417a6ccbbaf96fc2 - languageName: node - linkType: hard - -"typescript@patch:typescript@^4.7.4#~builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=7ad353" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 2eee5c37cad4390385db5db5a8e81470e42e8f1401b0358d7390095d6f681b410f2c4a0c496c6ff9ebd775423c7785cdace7bcdad76c7bee283df3d9718c0f20 - languageName: node - linkType: hard - -"typewise-core@npm:^1.2, typewise-core@npm:^1.2.0": - version: 1.2.0 - resolution: "typewise-core@npm:1.2.0" - checksum: c21e83544546d1aba2f17377c25ae0eb571c2153b2e3705932515bef103dbe43e05d2286f238ad139341b1000da40583115a44cb5e69a2ef408572b13dab844b - languageName: node - linkType: hard - -"typewise@npm:^1.0.3": - version: 1.0.3 - resolution: "typewise@npm:1.0.3" - dependencies: - typewise-core: ^1.2.0 - checksum: eb3452b1387df8bf8e3b620720d240425a50ce402d7c064c21ac4b5d88c551ee4d1f26cd649b8a17a6d06f7a3675733de841723f8e06bb3edabfeacc4924af4a - languageName: node - linkType: hard - -"typewiselite@npm:~1.0.0": - version: 1.0.0 - resolution: "typewiselite@npm:1.0.0" - checksum: 2e13a652c041680e9e37501129715f97c2ff2b8f52b5e82acd9355c070ca7c126633ff96d2ad03945254c271c0d1cf9f4956090c93ad750717e00d100cbd0c87 + resolution: "typescript@patch:typescript@npm%3A3.9.10#~builtin::version=3.9.10&hash=7ad353" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: dc7141ab555b23a8650a6787f98845fc11692063d02b75ff49433091b3af2fe3d773650dea18389d7c21f47d620fb3b110ea363dab4ab039417a6ccbbaf96fc2 languageName: node linkType: hard -"typical@npm:^2.6.0, typical@npm:^2.6.1": - version: 2.6.1 - resolution: "typical@npm:2.6.1" - checksum: 6af04fefe50d90d3471f058b2cdc0f49b7436bdd605cd00acea7965926ff388a5a7d692ef144f45fccee6f8e896c065702ecc44b69057e2ce88c09e897c7d3a4 +"typescript@patch:typescript@^4.7.4#~builtin": + version: 4.9.5 + resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=7ad353" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 2eee5c37cad4390385db5db5a8e81470e42e8f1401b0358d7390095d6f681b410f2c4a0c496c6ff9ebd775423c7785cdace7bcdad76c7bee283df3d9718c0f20 languageName: node linkType: hard @@ -16441,13 +11230,6 @@ __metadata: languageName: node linkType: hard -"ultron@npm:~1.1.0": - version: 1.1.1 - resolution: "ultron@npm:1.1.1" - checksum: aa7b5ebb1b6e33287b9d873c6756c4b7aa6d1b23d7162ff25b0c0ce5c3c7e26e2ab141a5dc6e96c10ac4d00a372e682ce298d784f06ffcd520936590b4bc0653 - languageName: node - linkType: hard - "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -16460,13 +11242,6 @@ __metadata: languageName: node linkType: hard -"underscore@npm:1.9.1": - version: 1.9.1 - resolution: "underscore@npm:1.9.1" - checksum: bee6f587661a6a9ca2f77e611896141e0287af51d8ca6034b11d0d4163ddbdd181a9720078ddbe94d265b7694f4880bc7f4c2ad260cfb8985ee2f9adcf13df03 - languageName: node - linkType: hard - "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" @@ -16497,18 +11272,6 @@ __metadata: languageName: node linkType: hard -"union-value@npm:^1.0.0": - version: 1.0.1 - resolution: "union-value@npm:1.0.1" - dependencies: - arr-union: ^3.1.0 - get-value: ^2.0.6 - is-extendable: ^0.1.1 - set-value: ^2.0.1 - checksum: a3464097d3f27f6aa90cf103ed9387541bccfc006517559381a10e0dffa62f465a9d9a09c9b9c3d26d0f4cbe61d4d010e2fbd710fd4bf1267a768ba8a774b0ba - languageName: node - linkType: hard - "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -16541,30 +11304,13 @@ __metadata: languageName: node linkType: hard -"unorm@npm:^1.3.3": - version: 1.6.0 - resolution: "unorm@npm:1.6.0" - checksum: 9a86546256a45f855b6cfe719086785d6aada94f63778cecdecece8d814ac26af76cb6da70130da0a08b8803bbf0986e56c7ec4249038198f3de02607fffd811 - languageName: node - linkType: hard - -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": +"unpipe@npm:1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0" checksum: 4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 languageName: node linkType: hard -"unset-value@npm:^1.0.0": - version: 1.0.0 - resolution: "unset-value@npm:1.0.0" - dependencies: - has-value: ^0.3.1 - isobject: ^3.0.0 - checksum: 5990ecf660672be2781fc9fb322543c4aa592b68ed9a3312fa4df0e9ba709d42e823af090fc8f95775b4cd2c9a5169f7388f0cec39238b6d0d55a69fc2ab6b29 - languageName: node - linkType: hard - "uri-js@npm:^4.2.2, uri-js@npm:^4.4.1": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -16574,29 +11320,6 @@ __metadata: languageName: node linkType: hard -"urix@npm:^0.1.0": - version: 0.1.0 - resolution: "urix@npm:0.1.0" - checksum: 4c076ecfbf3411e888547fe844e52378ab5ada2d2f27625139011eada79925e77f7fbf0e4016d45e6a9e9adb6b7e64981bd49b22700c7c401c5fc15f423303b3 - languageName: node - linkType: hard - -"url-parse-lax@npm:^3.0.0": - version: 3.0.0 - resolution: "url-parse-lax@npm:3.0.0" - dependencies: - prepend-http: ^2.0.0 - checksum: 1040e357750451173132228036aff1fd04abbd43eac1fb3e4fca7495a078bcb8d33cb765fe71ad7e473d9c94d98fd67adca63bd2716c815a2da066198dd37217 - languageName: node - linkType: hard - -"url-set-query@npm:^1.0.0": - version: 1.0.0 - resolution: "url-set-query@npm:1.0.0" - checksum: 5ad73525e8f3ab55c6bf3ddc70a43912e65ff9ce655d7868fdcefdf79f509cfdddde4b07150797f76186f1a47c0ecd2b7bb3687df8f84757dee4110cf006e12d - languageName: node - linkType: hard - "url@npm:^0.11.0": version: 0.11.3 resolution: "url@npm:0.11.3" @@ -16607,13 +11330,6 @@ __metadata: languageName: node linkType: hard -"use@npm:^3.1.0": - version: 3.1.1 - resolution: "use@npm:3.1.1" - checksum: 08a130289f5238fcbf8f59a18951286a6e660d17acccc9d58d9b69dfa0ee19aa038e8f95721b00b432c36d1629a9e32a464bf2e7e0ae6a244c42ddb30bdd8b33 - languageName: node - linkType: hard - "utf-8-validate@npm:5.0.7": version: 5.0.7 resolution: "utf-8-validate@npm:5.0.7" @@ -16624,17 +11340,7 @@ __metadata: languageName: node linkType: hard -"utf-8-validate@npm:^5.0.2": - version: 5.0.10 - resolution: "utf-8-validate@npm:5.0.10" - dependencies: - node-gyp: latest - node-gyp-build: ^4.3.0 - checksum: 5579350a023c66a2326752b6c8804cc7b39dcd251bb088241da38db994b8d78352e388dcc24ad398ab98385ba3c5ffcadb6b5b14b2637e43f767869055e46ba6 - languageName: node - linkType: hard - -"utf8@npm:3.0.0, utf8@npm:^3.0.0": +"utf8@npm:3.0.0": version: 3.0.0 resolution: "utf8@npm:3.0.0" checksum: cb89a69ad9ab393e3eae9b25305b3ff08bebca9adc839191a34f90777eb2942f86a96369d2839925fea58f8f722f7e27031d697f10f5f39690f8c5047303e62d @@ -16648,37 +11354,6 @@ __metadata: languageName: node linkType: hard -"util.promisify@npm:^1.0.0": - version: 1.1.2 - resolution: "util.promisify@npm:1.1.2" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - for-each: ^0.3.3 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - object.getownpropertydescriptors: ^2.1.6 - safe-array-concat: ^1.0.0 - checksum: 9a5233e7fd067ca24abe2310f9c93e6df3adb644a662fcd826454d30539d3dd1d557b75bfed4cedd4993203012ea6add6d7dd268fed35bbdac4736dce9446373 - languageName: node - linkType: hard - -"utils-merge@npm:1.0.1": - version: 1.0.1 - resolution: "utils-merge@npm:1.0.1" - checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 - languageName: node - linkType: hard - -"uuid@npm:3.3.2": - version: 3.3.2 - resolution: "uuid@npm:3.3.2" - bin: - uuid: ./bin/uuid - checksum: 8793629d2799f500aeea9fcd0aec6c4e9fbcc4d62ed42159ad96be345c3fffac1bbf61a23e18e2782600884fee05e6d4012ce4b70d0037c8e987533ae6a77870 - languageName: node - linkType: hard - "uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0" @@ -16711,23 +11386,6 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1": - version: 3.0.4 - resolution: "validate-npm-package-license@npm:3.0.4" - dependencies: - spdx-correct: ^3.0.0 - spdx-expression-parse: ^3.0.0 - checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad - languageName: node - linkType: hard - -"varint@npm:^5.0.0": - version: 5.0.2 - resolution: "varint@npm:5.0.2" - checksum: e1a66bf9a6cea96d1f13259170d4d41b845833acf3a9df990ea1e760d279bd70d5b1f4c002a50197efd2168a2fd43eb0b808444600fd4d23651e8d42fe90eb05 - languageName: node - linkType: hard - "varint@npm:^6.0.0": version: 6.0.0 resolution: "varint@npm:6.0.0" @@ -16735,13 +11393,6 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:~1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b - languageName: node - linkType: hard - "verror@npm:1.10.0": version: 1.10.0 resolution: "verror@npm:1.10.0" @@ -16783,301 +11434,7 @@ __metadata: languageName: node linkType: hard -"web3-bzz@npm:1.2.11": - version: 1.2.11 - resolution: "web3-bzz@npm:1.2.11" - dependencies: - "@types/node": ^12.12.6 - got: 9.6.0 - swarm-js: ^0.1.40 - underscore: 1.9.1 - checksum: 45136e7282819260357efdcdf6d81cb7b733b212aa1e46f1bbcaff70a33a2e3f6558936e6e1fc3bf75bb4c3220f844fc6b9d5bfaaa68a2f6ed0e8c0b02c97523 - languageName: node - linkType: hard - -"web3-core-helpers@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-helpers@npm:1.2.11" - dependencies: - underscore: 1.9.1 - web3-eth-iban: 1.2.11 - web3-utils: 1.2.11 - checksum: dac2ab85b8bec8251647d40f1dc5fcf30b2245de6d216328c51c9d619d12a567906c5bf8b542846552a56bf969edcfcb16fb67e3780461195df85cd506591f68 - languageName: node - linkType: hard - -"web3-core-method@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-method@npm:1.2.11" - dependencies: - "@ethersproject/transactions": ^5.0.0-beta.135 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - web3-core-promievent: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-utils: 1.2.11 - checksum: 7533c5b8c42df49969b9c95a2c9cb0abcd55a304ef4b276a5cc43673d27ffd9767a0caabe09271979b5afd0f788a51416f7018bc704d734ad78846c68dba15a7 - languageName: node - linkType: hard - -"web3-core-promievent@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-promievent@npm:1.2.11" - dependencies: - eventemitter3: 4.0.4 - checksum: bd3661978f252ec0033881b32a5d4dec1bfeb7fb0f018d77c077c77b60c0f965215dcbd54c5fcbef739441dd7efbdbd6c9b20e275e05f5b4d2cee762937d95cc - languageName: node - linkType: hard - -"web3-core-requestmanager@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-requestmanager@npm:1.2.11" - dependencies: - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - web3-providers-http: 1.2.11 - web3-providers-ipc: 1.2.11 - web3-providers-ws: 1.2.11 - checksum: 84898bfec26319d06ccf7ae63821b7fbea8efc8a76015921530cc4eb85db39598c16598f1e51f95ed79146d7defafe7b924b5c6f6927fb2a153d01eb0862182c - languageName: node - linkType: hard - -"web3-core-subscriptions@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core-subscriptions@npm:1.2.11" - dependencies: - eventemitter3: 4.0.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - checksum: 7c8c07ea79fc9cf4ecb15ea37c5db38cc38e4b0545247d9ccc7ff6f4257565c03bcee569695a93abe02b8a98a6a9c227df880911ae324c0c6218a9571a3811f6 - languageName: node - linkType: hard - -"web3-core@npm:1.2.11": - version: 1.2.11 - resolution: "web3-core@npm:1.2.11" - dependencies: - "@types/bn.js": ^4.11.5 - "@types/node": ^12.12.6 - bignumber.js: ^9.0.0 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-requestmanager: 1.2.11 - web3-utils: 1.2.11 - checksum: 1793affddb4fa811f9781dc644b4017d95c6084a21bb866e0dc626f6d48bfc29eacf02237608b587ca49094e9342da878b64173510d99a6e9171f7a697e8cb36 - languageName: node - linkType: hard - -"web3-eth-abi@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-abi@npm:1.2.11" - dependencies: - "@ethersproject/abi": 5.0.0-beta.153 - underscore: 1.9.1 - web3-utils: 1.2.11 - checksum: ef96c9c0faad2634d69f1c6dbf3414d0f292c0e534e477f47a1b14512c7099237a09d6b6ba91b624cea348e51e759106b128b0fe463d62f17f447e0a47071d76 - languageName: node - linkType: hard - -"web3-eth-accounts@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-accounts@npm:1.2.11" - dependencies: - crypto-browserify: 3.12.0 - eth-lib: 0.2.8 - ethereumjs-common: ^1.3.2 - ethereumjs-tx: ^2.1.1 - scrypt-js: ^3.0.1 - underscore: 1.9.1 - uuid: 3.3.2 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-utils: 1.2.11 - checksum: 1653a7548337b538b280ced0d25dbf8b105954a5bf61726d5def25128ffc87c49d0d38b678a32e7d259e687f5e72cc452d92e14eaa8c9976a9153347e4afe7eb - languageName: node - linkType: hard - -"web3-eth-contract@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-contract@npm:1.2.11" - dependencies: - "@types/bn.js": ^4.11.5 - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-promievent: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-eth-abi: 1.2.11 - web3-utils: 1.2.11 - checksum: 1dc74e11f09c895bd5b26c5dfb3a0818d6a38a573de9252a3a943acf6ba88a058313e2977c95564ab56c3696f1ca975237ae4f10c93d34d2978f11bb1119b4d7 - languageName: node - linkType: hard - -"web3-eth-ens@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-ens@npm:1.2.11" - dependencies: - content-hash: ^2.5.2 - eth-ens-namehash: 2.0.8 - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-promievent: 1.2.11 - web3-eth-abi: 1.2.11 - web3-eth-contract: 1.2.11 - web3-utils: 1.2.11 - checksum: 987999713c5c79f23a67ad244813212e9582566f6a7665312f887ce0eda77d91b85d3c0df21af14ef6ab6e970626d5d02129a2df3a8c257151f9540d6968a748 - languageName: node - linkType: hard - -"web3-eth-iban@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-iban@npm:1.2.11" - dependencies: - bn.js: ^4.11.9 - web3-utils: 1.2.11 - checksum: 1c28b3ad2cad2af0a76b051fe2c05ed933476eaa99f2c245862f66d4e3d56e60ad26cf55120513f78648ab1ff2b8a6b751e63448cdb01b53b542334bf148286f - languageName: node - linkType: hard - -"web3-eth-personal@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth-personal@npm:1.2.11" - dependencies: - "@types/node": ^12.12.6 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-net: 1.2.11 - web3-utils: 1.2.11 - checksum: a754a16aaed1e97baf963f594b69c83bc4c1cf3f5b181b18720ce292583b4a1b70c7a5c22433679c3e66166773bb43731535d085db3bcfc72af48290553f5122 - languageName: node - linkType: hard - -"web3-eth@npm:1.2.11": - version: 1.2.11 - resolution: "web3-eth@npm:1.2.11" - dependencies: - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-eth-abi: 1.2.11 - web3-eth-accounts: 1.2.11 - web3-eth-contract: 1.2.11 - web3-eth-ens: 1.2.11 - web3-eth-iban: 1.2.11 - web3-eth-personal: 1.2.11 - web3-net: 1.2.11 - web3-utils: 1.2.11 - checksum: eaf361bc59859e7e9078e57f438564f10ea5c0cc00404d3ccf537f3c8d11d963b74f8c3981f4160f1ed2e3c4d9d97a5ff85b33744d5083afde8dfd5dde887034 - languageName: node - linkType: hard - -"web3-net@npm:1.2.11": - version: 1.2.11 - resolution: "web3-net@npm:1.2.11" - dependencies: - web3-core: 1.2.11 - web3-core-method: 1.2.11 - web3-utils: 1.2.11 - checksum: 76a99815699674709b869b60bf950d20167b999fe93f7d091b01ce3fd0e3dd9c30ef3519156c04eb01703791c049b19b295e6901dd41d208ea600149961f7ee6 - languageName: node - linkType: hard - -"web3-provider-engine@npm:14.2.1": - version: 14.2.1 - resolution: "web3-provider-engine@npm:14.2.1" - dependencies: - async: ^2.5.0 - backoff: ^2.5.0 - clone: ^2.0.0 - cross-fetch: ^2.1.0 - eth-block-tracker: ^3.0.0 - eth-json-rpc-infura: ^3.1.0 - eth-sig-util: ^1.4.2 - ethereumjs-block: ^1.2.2 - ethereumjs-tx: ^1.2.0 - ethereumjs-util: ^5.1.5 - ethereumjs-vm: ^2.3.4 - json-rpc-error: ^2.0.0 - json-stable-stringify: ^1.0.1 - promise-to-callback: ^1.0.0 - readable-stream: ^2.2.9 - request: ^2.85.0 - semaphore: ^1.0.3 - ws: ^5.1.1 - xhr: ^2.2.0 - xtend: ^4.0.1 - checksum: 45441e22633184bd5f6ea645e20f99c8002b3b64d3e564cd9d0f65bad7f0755ad2cdf9a88fcac9585e908aacea28cc6e80c0939498ee4f4c6c49107d16e011bf - languageName: node - linkType: hard - -"web3-providers-http@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-http@npm:1.2.11" - dependencies: - web3-core-helpers: 1.2.11 - xhr2-cookies: 1.1.0 - checksum: 64760032d68826865de084c31d81be70bebc54cd82138ef724da13b60f7b341d4c0c6716912616b928680756ea6f2cef42be7d16fa9dd143a09ac55701232193 - languageName: node - linkType: hard - -"web3-providers-ipc@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-ipc@npm:1.2.11" - dependencies: - oboe: 2.1.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - checksum: 0fab2f824e4c7f080fee26b76c9c8448eb51abfd285a04f3c9efe92c3b9a8742096804ec02f56bc8297e375ea12f0f2205bb6c0ae376c44c005cdfeec65d0b7e - languageName: node - linkType: hard - -"web3-providers-ws@npm:1.2.11": - version: 1.2.11 - resolution: "web3-providers-ws@npm:1.2.11" - dependencies: - eventemitter3: 4.0.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - websocket: ^1.0.31 - checksum: 4a4c591c2bd9724748e9dba124e59048b91239aa7cd435394f2a1d8e7914132920a17e56bc646f46912844fcfbbc38333b7023ebec298af36106ec4814d2ff5c - languageName: node - linkType: hard - -"web3-shh@npm:1.2.11": - version: 1.2.11 - resolution: "web3-shh@npm:1.2.11" - dependencies: - web3-core: 1.2.11 - web3-core-method: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-net: 1.2.11 - checksum: 64c4a1f03bc3975a2baff9fa6d89a0050a06f179f1ec4d6e28f480b761d0efe56a9a79a5a320821e1dd503e82d44e73dd69b883b9e69d96cced3f979e0a3f4ff - languageName: node - linkType: hard - -"web3-utils@npm:1.2.11": - version: 1.2.11 - resolution: "web3-utils@npm:1.2.11" - dependencies: - bn.js: ^4.11.9 - eth-lib: 0.2.8 - ethereum-bloom-filters: ^1.0.6 - ethjs-unit: 0.1.6 - number-to-bn: 1.7.0 - randombytes: ^2.1.0 - underscore: 1.9.1 - utf8: 3.0.0 - checksum: 1e43235963d5176e447b20b201a66fabccbe7bd4ef8bbb2edfa5ea80a41e8202a8e8f3db128b2a1662855a627a52d100e3207b81a739b937b5b3b4f9114c008f - languageName: node - linkType: hard - -"web3-utils@npm:^1.0.0-beta.31, web3-utils@npm:^1.3.6": +"web3-utils@npm:^1.3.6": version: 1.10.4 resolution: "web3-utils@npm:1.10.4" dependencies: @@ -17093,21 +11450,6 @@ __metadata: languageName: node linkType: hard -"web3@npm:1.2.11": - version: 1.2.11 - resolution: "web3@npm:1.2.11" - dependencies: - web3-bzz: 1.2.11 - web3-core: 1.2.11 - web3-eth: 1.2.11 - web3-eth-personal: 1.2.11 - web3-net: 1.2.11 - web3-shh: 1.2.11 - web3-utils: 1.2.11 - checksum: c4fa6ddaddc2de31c561590eb3703e9446c0a9bd87155f536fd72c3c22337056bbd045baf36fec6152e58ae67e552fffad29e794030cd87634becb99a079e91f - languageName: node - linkType: hard - "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -17115,41 +11457,6 @@ __metadata: languageName: node linkType: hard -"websocket@npm:1.0.32": - version: 1.0.32 - resolution: "websocket@npm:1.0.32" - dependencies: - bufferutil: ^4.0.1 - debug: ^2.2.0 - es5-ext: ^0.10.50 - typedarray-to-buffer: ^3.1.5 - utf-8-validate: ^5.0.2 - yaeti: ^0.0.6 - checksum: a29777a1942bf802f955782c7cf948797d19731a911b81adb957873e74b1d5356c621f217a972b075ecf04417a76897ea98dbfc19394007c4cf5e97cd4d494ac - languageName: node - linkType: hard - -"websocket@npm:^1.0.31": - version: 1.0.35 - resolution: "websocket@npm:1.0.35" - dependencies: - bufferutil: ^4.0.1 - debug: ^2.2.0 - es5-ext: ^0.10.63 - typedarray-to-buffer: ^3.1.5 - utf-8-validate: ^5.0.2 - yaeti: ^0.0.6 - checksum: 760ad7b090dee914336069cdf4fb78c1a96f5a452b2a5459b68d596af088959bb48113914667123d9662388c0398980955c875c950177c51fcf0d22cc92d935c - languageName: node - linkType: hard - -"whatwg-fetch@npm:^2.0.4": - version: 2.0.4 - resolution: "whatwg-fetch@npm:2.0.4" - checksum: de7c65a68d7d62e2f144a6b30293370b3ad82b65ebcd68f2ac8e8bbe7ede90febd98ba9486b78c1cbc950e0e8838fa5c2727f939899ab3fc7b71a04be52d33a5 - languageName: node - linkType: hard - "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -17173,13 +11480,6 @@ __metadata: languageName: node linkType: hard -"which-module@npm:^1.0.0": - version: 1.0.0 - resolution: "which-module@npm:1.0.0" - checksum: 98434f7deb36350cb543c1f15612188541737e1f12d39b23b1c371dff5cf4aa4746210f2bdec202d5fe9da8682adaf8e3f7c44c520687d30948cfc59d5534edb - languageName: node - linkType: hard - "which-module@npm:^2.0.0": version: 2.0.1 resolution: "which-module@npm:2.0.1" @@ -17242,15 +11542,6 @@ __metadata: languageName: node linkType: hard -"window-size@npm:^0.2.0": - version: 0.2.0 - resolution: "window-size@npm:0.2.0" - bin: - window-size: cli.js - checksum: a85e2acf156cfa194301294809867bdadd8a48ee5d972d9fa8e3e1b3420a1d0201b13ac8eb0348a0d14bbf2c3316565b6a749749c2384c5d286caf8a064c4f90 - languageName: node - linkType: hard - "word-wrap@npm:^1.2.5, word-wrap@npm:~1.2.3": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -17293,16 +11584,6 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^2.0.0": - version: 2.1.0 - resolution: "wrap-ansi@npm:2.1.0" - dependencies: - string-width: ^1.0.1 - strip-ansi: ^3.0.1 - checksum: 2dacd4b3636f7a53ee13d4d0fe7fa2ed9ad81e9967e17231924ea88a286ec4619a78288de8d41881ee483f4449ab2c0287cde8154ba1bd0126c10271101b2ee3 - languageName: node - linkType: hard - "wrap-ansi@npm:^5.1.0": version: 5.1.0 resolution: "wrap-ansi@npm:5.1.0" @@ -17386,26 +11667,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^3.0.0": - version: 3.3.3 - resolution: "ws@npm:3.3.3" - dependencies: - async-limiter: ~1.0.0 - safe-buffer: ~5.1.0 - ultron: ~1.1.0 - checksum: 20b7bf34bb88715b9e2d435b76088d770e063641e7ee697b07543815fabdb752335261c507a973955e823229d0af8549f39cc669825e5c8404aa0422615c81d9 - languageName: node - linkType: hard - -"ws@npm:^5.1.1": - version: 5.2.4 - resolution: "ws@npm:5.2.4" - dependencies: - async-limiter: ~1.0.0 - checksum: a0c39704a752593ce603b0b3d28a3d3901839cd20560503b2c7257d63ee448677a4e00a2b7f69d775363a08700f041e84fe1f77b00931bb471f54380ab6dd50e - languageName: node - linkType: hard - "ws@npm:^7.4.5, ws@npm:^7.4.6": version: 7.5.10 resolution: "ws@npm:7.5.10" @@ -17421,74 +11682,13 @@ __metadata: languageName: node linkType: hard -"xhr-request-promise@npm:^0.1.2": - version: 0.1.3 - resolution: "xhr-request-promise@npm:0.1.3" - dependencies: - xhr-request: ^1.1.0 - checksum: 2e127c0de063db0aa704b8d5b805fd34f0f07cac21284a88c81f96727eb71af7d2dfa3ad43e96ed3e851e05a1bd88933048ec183378b48594dfbead1c9043aee - languageName: node - linkType: hard - -"xhr-request@npm:^1.0.1, xhr-request@npm:^1.1.0": - version: 1.1.0 - resolution: "xhr-request@npm:1.1.0" - dependencies: - buffer-to-arraybuffer: ^0.0.5 - object-assign: ^4.1.1 - query-string: ^5.0.1 - simple-get: ^2.7.0 - timed-out: ^4.0.1 - url-set-query: ^1.0.0 - xhr: ^2.0.4 - checksum: fd8186f33e8696dabcd1ad2983f8125366f4cd799c6bf30aa8d942ac481a7e685a5ee8c38eeee6fca715a7084b432a3a326991375557dc4505c928d3f7b0f0a8 - languageName: node - linkType: hard - -"xhr2-cookies@npm:1.1.0": - version: 1.1.0 - resolution: "xhr2-cookies@npm:1.1.0" - dependencies: - cookiejar: ^2.1.1 - checksum: 6a9fc45f3490cc53e6a308bd7164dab07ecb94f6345e78951ed4a1e8f8c4c7707a1b039a6b4ef7c9d611d9465d6f94d7d4260c43bc34eed8d6f9210a775eb719 - languageName: node - linkType: hard - -"xhr@npm:^2.0.4, xhr@npm:^2.2.0, xhr@npm:^2.3.3": - version: 2.6.0 - resolution: "xhr@npm:2.6.0" - dependencies: - global: ~4.4.0 - is-function: ^1.0.1 - parse-headers: ^2.0.0 - xtend: ^4.0.0 - checksum: a1db277e37737caf3ed363d2a33ce4b4ea5b5fc190b663a6f70bc252799185b840ccaa166eaeeea4841c9c60b87741f0a24e29cbcf6708dd425986d4df186d2f - languageName: node - linkType: hard - -"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": +"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:^4.0.2, xtend@npm:~4.0.0": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a languageName: node linkType: hard -"xtend@npm:~2.1.1": - version: 2.1.2 - resolution: "xtend@npm:2.1.2" - dependencies: - object-keys: ~0.4.0 - checksum: a8b79f31502c163205984eaa2b196051cd2fab0882b49758e30f2f9018255bc6c462e32a090bf3385d1bda04755ad8cc0052a09e049b0038f49eb9b950d9c447 - languageName: node - linkType: hard - -"y18n@npm:^3.2.1": - version: 3.2.2 - resolution: "y18n@npm:3.2.2" - checksum: 6154fd7544f8bbf5b18cdf77692ed88d389be49c87238ecb4e0d6a5276446cd2a5c29cc4bdbdddfc7e4e498b08df9d7e38df4a1453cf75eecfead392246ea74a - languageName: node - linkType: hard - "y18n@npm:^4.0.0": version: 4.0.3 resolution: "y18n@npm:4.0.3" @@ -17503,14 +11703,7 @@ __metadata: languageName: node linkType: hard -"yaeti@npm:^0.0.6": - version: 0.0.6 - resolution: "yaeti@npm:0.0.6" - checksum: 6db12c152f7c363b80071086a3ebf5032e03332604eeda988872be50d6c8469e1f13316175544fa320f72edad696c2d83843ad0ff370659045c1a68bcecfcfea - languageName: node - linkType: hard - -"yallist@npm:^3.0.0, yallist@npm:^3.0.2, yallist@npm:^3.1.1": +"yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d @@ -17558,16 +11751,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^2.4.1": - version: 2.4.1 - resolution: "yargs-parser@npm:2.4.1" - dependencies: - camelcase: ^3.0.0 - lodash.assign: ^4.0.6 - checksum: f57946a93a9e0986fccbc7999a3fc8179d4693e4551ef0ace3d599c38ec004a3783efb9eed9fa5d738b30db1cfa1d3a07f4dd6ae060cfce6fe61c3ae7b7a347b - languageName: node - linkType: hard - "yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" @@ -17621,28 +11804,6 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^4.7.1": - version: 4.8.1 - resolution: "yargs@npm:4.8.1" - dependencies: - cliui: ^3.2.0 - decamelize: ^1.1.1 - get-caller-file: ^1.0.1 - lodash.assign: ^4.0.3 - os-locale: ^1.4.0 - read-pkg-up: ^1.0.1 - require-directory: ^2.1.1 - require-main-filename: ^1.0.1 - set-blocking: ^2.0.0 - string-width: ^1.0.1 - which-module: ^1.0.0 - window-size: ^0.2.0 - y18n: ^3.2.1 - yargs-parser: ^2.4.1 - checksum: 5d0a45dceaf8cff1c6a7164b2c944755a09cced3cb1d585bbc79ffed758ef9f9b54ead0879e3dacfc696ccd15fec9e6e29183c24517d7f578b47cd0614a3851d - languageName: node - linkType: hard - "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1"