diff --git a/spot-vaults/.openzeppelin/mainnet.json b/spot-vaults/.openzeppelin/mainnet.json index f7e88223..bd24ff53 100644 --- a/spot-vaults/.openzeppelin/mainnet.json +++ b/spot-vaults/.openzeppelin/mainnet.json @@ -5,6 +5,11 @@ "address": "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB", "txHash": "0x7b991de0ac1a42dc8b2d2ba290f0c36ed40d9433d06af0a726e36f723a561fe2", "kind": "transparent" + }, + { + "address": "0x6f60625c5B4Bdf89b9F18B9c681310E6B3dAcDbD", + "txHash": "0x0f2bb0b3e4f47f23838fdcf6062ef273e2b5dd03e06c41166f8857272ef24e1c", + "kind": "transparent" } ], "impls": { @@ -1283,6 +1288,329 @@ }, "namespaces": {} } + }, + "625b0bbf06f5cc4dd25c6f8d9b6bea67b59d5ed0c3eb5a35af6bb9c0a252db8b": { + "address": "0x7e6f463765cf20cb3bD3ac437cFde89c157a4223", + "txHash": "0x1abe1cf66b7345e699f8800c4a9eacb86451e13745d003d821e5cd182084af66", + "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": "underlying", + "offset": 0, + "slot": "301", + "type": "t_contract(IERC20Upgradeable)1950", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:83" + }, + { + "label": "perp", + "offset": 0, + "slot": "302", + "type": "t_contract(IPerpetualTranche)413", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:86" + }, + { + "label": "stampl", + "offset": 0, + "slot": "303", + "type": "t_contract(IRolloverVault)501", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:89" + }, + { + "label": "underlyingUnitAmt", + "offset": 0, + "slot": "304", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:92" + }, + { + "label": "perpUnitAmt", + "offset": 0, + "slot": "305", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:95" + }, + { + "label": "keeper", + "offset": 0, + "slot": "306", + "type": "t_address", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:98" + }, + { + "label": "targetDR", + "offset": 0, + "slot": "307", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:101" + }, + { + "label": "equilibriumDR", + "offset": 0, + "slot": "308", + "type": "t_struct(Range)32_storage", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:106" + }, + { + "label": "lagFactorUnderlyingToPerp", + "offset": 0, + "slot": "310", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:109" + }, + { + "label": "lagFactorPerpToUnderlying", + "offset": 0, + "slot": "311", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:112" + }, + { + "label": "minRebalanceVal", + "offset": 0, + "slot": "312", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:115" + }, + { + "label": "rebalanceFreqSec", + "offset": 0, + "slot": "313", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:118" + }, + { + "label": "lastRebalanceTimestampSec", + "offset": 0, + "slot": "314", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:121" + }, + { + "label": "maxSwapFeePerc", + "offset": 0, + "slot": "315", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:124" + } + ], + "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)1950": { + "label": "contract IERC20Upgradeable", + "numberOfBytes": "20" + }, + "t_contract(IPerpetualTranche)413": { + "label": "contract IPerpetualTranche", + "numberOfBytes": "20" + }, + "t_contract(IRolloverVault)501": { + "label": "contract IRolloverVault", + "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(Range)32_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/.openzeppelin/sepolia.json b/spot-vaults/.openzeppelin/sepolia.json index 4e464dd5..203d361b 100644 --- a/spot-vaults/.openzeppelin/sepolia.json +++ b/spot-vaults/.openzeppelin/sepolia.json @@ -5,6 +5,11 @@ "address": "0xc3f6D1F1d253EdC8B34D78Bc6cDD2b3eEFAd76BD", "txHash": "0xe08468aac2fe4f178e7dbddd07de8bb8d4e8066358082aa0a17c1be74400ad7c", "kind": "transparent" + }, + { + "address": "0xB02114487836409136B0006A090995D63931C486", + "txHash": "0x2764db52ff079c7e1a6cbd293eb914089977ee9968c01cf8a9302aa660947ec9", + "kind": "transparent" } ], "impls": { @@ -645,6 +650,329 @@ }, "namespaces": {} } + }, + "625b0bbf06f5cc4dd25c6f8d9b6bea67b59d5ed0c3eb5a35af6bb9c0a252db8b": { + "address": "0x932Ba53192a3206825A9F9393FE669C9CEf7ee37", + "txHash": "0xac53eebc0ce079d2999b697eceaa933d68af6960c90a8b87690ce4d60549e4e0", + "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": "underlying", + "offset": 0, + "slot": "301", + "type": "t_contract(IERC20Upgradeable)1950", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:83" + }, + { + "label": "perp", + "offset": 0, + "slot": "302", + "type": "t_contract(IPerpetualTranche)413", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:86" + }, + { + "label": "stampl", + "offset": 0, + "slot": "303", + "type": "t_contract(IRolloverVault)501", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:89" + }, + { + "label": "underlyingUnitAmt", + "offset": 0, + "slot": "304", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:92" + }, + { + "label": "perpUnitAmt", + "offset": 0, + "slot": "305", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:95" + }, + { + "label": "keeper", + "offset": 0, + "slot": "306", + "type": "t_address", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:98" + }, + { + "label": "targetDR", + "offset": 0, + "slot": "307", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:101" + }, + { + "label": "equilibriumDR", + "offset": 0, + "slot": "308", + "type": "t_struct(Range)32_storage", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:106" + }, + { + "label": "lagFactorUnderlyingToPerp", + "offset": 0, + "slot": "310", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:109" + }, + { + "label": "lagFactorPerpToUnderlying", + "offset": 0, + "slot": "311", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:112" + }, + { + "label": "minRebalanceVal", + "offset": 0, + "slot": "312", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:115" + }, + { + "label": "rebalanceFreqSec", + "offset": 0, + "slot": "313", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:118" + }, + { + "label": "lastRebalanceTimestampSec", + "offset": 0, + "slot": "314", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:121" + }, + { + "label": "maxSwapFeePerc", + "offset": 0, + "slot": "315", + "type": "t_uint256", + "contract": "DRBalancerVault", + "src": "contracts/DRBalancerVault.sol:124" + } + ], + "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)1950": { + "label": "contract IERC20Upgradeable", + "numberOfBytes": "20" + }, + "t_contract(IPerpetualTranche)413": { + "label": "contract IPerpetualTranche", + "numberOfBytes": "20" + }, + "t_contract(IRolloverVault)501": { + "label": "contract IRolloverVault", + "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(Range)32_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/tasks/deploy.ts b/spot-vaults/tasks/deploy.ts index f7a1e2b8..6b48cb31 100644 --- a/spot-vaults/tasks/deploy.ts +++ b/spot-vaults/tasks/deploy.ts @@ -1,3 +1,4 @@ +import { getAdminAddress, getImplementationAddress } from "@openzeppelin/upgrades-core"; import { task, types } from "hardhat/config"; import { TaskArguments } from "hardhat/types"; import { sleep } from "./tools"; @@ -166,3 +167,87 @@ task("deploy:CharmManager") console.log("Skipping verification"); } }); + +task("deploy:DRBalancerVault") + .addParam( + "name", + "the ERC20 name of the vault LP token", + undefined, + types.string, + false, + ) + .addParam( + "symbol", + "the ERC20 symbol of the vault LP token", + undefined, + types.string, + false, + ) + .addParam( + "underlying", + "the address of the underlying token", + undefined, + types.string, + false, + ) + .addParam("perp", "the address of the perp token", undefined, types.string, false) + .addParam( + "rolloverVault", + "the address of the stAMPL rollover vault", + 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]; + const deployerAddress = await deployer.getAddress(); + console.log("Deployer:", deployerAddress); + + const { name, symbol, underlying, perp, rolloverVault, verify } = args; + + // Deploy proxy + console.log("\n--- Deploying DRBalancerVault proxy ---"); + const DRBalancerVault = await hre.ethers.getContractFactory("DRBalancerVault"); + const vault = await hre.upgrades.deployProxy( + DRBalancerVault.connect(deployer), + [name, symbol, underlying, perp, rolloverVault], + { + initializer: "init(string,string,address,address,address)", + }, + ); + await vault.waitForDeployment(); + const proxyAddress = vault.target; + console.log("DRBalancerVault proxy:", proxyAddress); + + // Get proxy admin and implementation addresses + const proxyAdminAddress = await getAdminAddress( + hre.ethers.provider, + proxyAddress as string, + ); + const implAddress = await getImplementationAddress( + hre.ethers.provider, + proxyAddress as string, + ); + console.log("ProxyAdmin:", proxyAdminAddress); + console.log("Implementation:", implAddress); + + // Verify contracts + if (verify) { + console.log("\n--- Verifying contracts ---"); + await sleep(30); + try { + await hre.run("verify:contract", { + address: proxyAddress, + }); + } catch (e) { + console.log("Verification failed (may already be verified):", e.message); + } + } + + console.log("\n--- Deployment Summary ---"); + console.log("DRBalancerVault proxy:", proxyAddress); + console.log("ProxyAdmin:", proxyAdminAddress); + console.log("Implementation:", implAddress); + console.log("Owner:", deployerAddress); + }); diff --git a/spot-vaults/tasks/info.ts b/spot-vaults/tasks/info.ts index 63a6f5c1..3d3d8771 100644 --- a/spot-vaults/tasks/info.ts +++ b/spot-vaults/tasks/info.ts @@ -191,6 +191,135 @@ task("info:BillBroker") } }); +task("info:DRBalancerVault") + .addPositionalParam( + "address", + "the address of the DR balancer vault contract", + undefined, + types.string, + false, + ) + .setAction(async function (args: TaskArguments, hre) { + const { address } = args; + + const vault = await hre.ethers.getContractAt("DRBalancerVault", address); + const vaultDecimals = await vault.DECIMALS(); + const drDecimals = await vault.DR_DECIMALS(); + const proxyAdminAddress = await getAdminAddress(hre.ethers.provider, address); + const implAddress = await getImplementationAddress(hre.ethers.provider, address); + + const underlying = await hre.ethers.getContractAt("ERC20", await vault.underlying()); + const underlyingDecimals = await underlying.decimals(); + const perp = await hre.ethers.getContractAt("ERC20", await vault.perp()); + const perpDecimals = await perp.decimals(); + const stampl = await vault.stampl(); + + console.log("---------------------------------------------------------------"); + console.log("DRBalancerVault:", vault.target); + console.log("owner:", await vault.owner()); + console.log("keeper:", await vault.keeper()); + console.log("proxyAdmin:", proxyAdminAddress); + console.log("implementation:", implAddress); + console.log("paused:", await vault.paused()); + + console.log("---------------------------------------------------------------"); + console.log("Tokens:"); + console.log("underlying:", underlying.target, `(${await underlying.symbol()})`); + console.log("perp:", perp.target, `(${await perp.symbol()})`); + console.log("stampl:", stampl); + + console.log("---------------------------------------------------------------"); + console.log("Configuration:"); + const targetDR = await vault.targetDR(); + const equilibriumDR = await vault.equilibriumDR(); + console.table([ + ["targetDR", pp(targetDR, drDecimals)], + ["equilibriumDR.lower", pp(equilibriumDR[0], drDecimals)], + ["equilibriumDR.upper", pp(equilibriumDR[1], drDecimals)], + ["lagFactorUnderlyingToPerp", (await vault.lagFactorUnderlyingToPerp()).toString()], + ["lagFactorPerpToUnderlying", (await vault.lagFactorPerpToUnderlying()).toString()], + ["minRebalanceVal", pp(await vault.minRebalanceVal(), underlyingDecimals)], + ["rebalanceFreqSec", (await vault.rebalanceFreqSec()).toString()], + ["maxSwapFeePerc", pp(await vault.maxSwapFeePerc(), vaultDecimals)], + ]); + + console.log("---------------------------------------------------------------"); + console.log("State:"); + const underlyingBal = await vault.underlyingBalance(); + const perpBal = await vault.perpBalance(); + const totalSupply = await vault.totalSupply(); + const lastRebalance = await vault.lastRebalanceTimestampSec(); + const lastRebalanceDate = + lastRebalance > 0 ? new Date(Number(lastRebalance) * 1000).toISOString() : "never"; + + console.table([ + ["underlyingBalance", pp(underlyingBal, underlyingDecimals)], + ["perpBalance", pp(perpBal, perpDecimals)], + ["totalSupply (notes)", pp(totalSupply, vaultDecimals)], + ["lastRebalanceTimestampSec", lastRebalance.toString()], + ["lastRebalanceDate", lastRebalanceDate], + ]); + + try { + const tvl = await vault.getTVL.staticCall(); + console.log("TVL (underlying denomination):", pp(tvl, underlyingDecimals)); + + const stamplContract = await hre.ethers.getContractAt("IRolloverVault", stampl); + const currentDR = await stamplContract.deviationRatio.staticCall(); + console.log("Current system DR:", pp(currentDR, drDecimals)); + + const [rebalanceAmt, isUnderlyingIntoPerp] = + await vault.computeRebalanceAmount.staticCall(); + console.log("---------------------------------------------------------------"); + console.log("Rebalance Preview:"); + console.log("rebalanceAmount:", pp(rebalanceAmt, underlyingDecimals)); + console.log( + "direction:", + isUnderlyingIntoPerp + ? "underlying -> perp (mint)" + : "perp -> underlying (redeem)", + ); + + // Check if rebalance is pokable + console.log("---------------------------------------------------------------"); + console.log("Rebalance Pokability:"); + + const currentTimestamp = Math.floor(Date.now() / 1000); + const rebalanceFreq = Number(await vault.rebalanceFreqSec()); + const nextRebalanceTimestamp = Number(lastRebalance) + rebalanceFreq; + const timeElapsed = currentTimestamp >= nextRebalanceTimestamp; + const secondsUntilPokable = timeElapsed + ? 0 + : nextRebalanceTimestamp - currentTimestamp; + + const equilibriumDR = await vault.equilibriumDR(); + const inEquilibriumZone = + currentDR >= equilibriumDR[0] && currentDR <= equilibriumDR[1]; + + console.table([ + ["timeElapsed", timeElapsed], + ["secondsUntilPokable", secondsUntilPokable], + ["inEquilibriumZone", inEquilibriumZone], + ["hasRebalanceAmount", rebalanceAmt > 0n], + ]); + + // Try static call to see if rebalance would succeed + let rebalanceExecutable = false; + try { + await vault.rebalance.staticCall(); + rebalanceExecutable = true; + } catch (e) { + // rebalance not executable + } + console.log("rebalanceExecutable:", rebalanceExecutable); + } catch (e) { + console.log(e); + console.log("Unable to fetch dynamic state (TVL/DR/rebalance)"); + } + + console.log("---------------------------------------------------------------"); + }); + task("info:WethWamplManager") .addPositionalParam( "address", diff --git a/spot-vaults/tasks/ops.ts b/spot-vaults/tasks/ops.ts index 4283edb4..6848e578 100644 --- a/spot-vaults/tasks/ops.ts +++ b/spot-vaults/tasks/ops.ts @@ -414,3 +414,231 @@ task("ops:swapPerpsForUSD") ethers.formatUnits(await perp.balanceOf(signerAddress), await perp.decimals()), ); }); + +task("ops:drVaultRebalance", "Calls rebalance on DRBalancerVault") + .addParam( + "address", + "the address of the DRBalancerVault contract", + undefined, + types.string, + false, + ) + .setAction(async function (args: TaskArguments, hre) { + const signer = (await hre.ethers.getSigners())[0]; + const signerAddress = await signer.getAddress(); + console.log("Signer", signerAddress); + + const { address } = args; + const vault = await hre.ethers.getContractAt("DRBalancerVault", address); + const underlying = await hre.ethers.getContractAt("ERC20", await vault.underlying()); + const perp = await hre.ethers.getContractAt("ERC20", await vault.perp()); + const stampl = await hre.ethers.getContractAt("IRolloverVault", await vault.stampl()); + const underlyingDecimals = await underlying.decimals(); + const perpDecimals = await perp.decimals(); + const drDecimals = await vault.DR_DECIMALS(); + + console.log("---------------------------------------------------------------"); + console.log("State before rebalance:"); + const drBefore = await stampl.deviationRatio.staticCall(); + console.log("System DR:", ethers.formatUnits(drBefore, drDecimals)); + console.log( + "Vault underlying balance:", + ethers.formatUnits(await vault.underlyingBalance(), underlyingDecimals), + ); + console.log( + "Vault perp balance:", + ethers.formatUnits(await vault.perpBalance(), perpDecimals), + ); + + const lastRebalance = await vault.lastRebalanceTimestampSec(); + const rebalanceFreq = await vault.rebalanceFreqSec(); + const nextRebalanceTime = Number(lastRebalance) + Number(rebalanceFreq); + const now = Math.floor(Date.now() / 1000); + console.log( + "Last rebalance:", + lastRebalance > 0 ? new Date(Number(lastRebalance) * 1000).toISOString() : "never", + ); + console.log("Rebalance frequency (sec):", rebalanceFreq.toString()); + console.log( + "Can rebalance:", + now >= nextRebalanceTime ? "yes" : `no (wait ${nextRebalanceTime - now}s)`, + ); + + console.log("---------------------------------------------------------------"); + console.log("Rebalance preview:"); + try { + const [rebalanceAmt, isUnderlyingIntoPerp] = + await vault.computeRebalanceAmount.staticCall(); + console.log( + "Rebalance amount:", + ethers.formatUnits(rebalanceAmt, underlyingDecimals), + ); + console.log( + "Direction:", + isUnderlyingIntoPerp + ? "underlying -> perp (mint)" + : "perp -> underlying (redeem)", + ); + + if (rebalanceAmt === 0n) { + console.log( + "No rebalance needed (within equilibrium range or insufficient liquidity)", + ); + return; + } + } catch (e) { + console.log("Unable to preview rebalance:", e.message); + } + + console.log("---------------------------------------------------------------"); + console.log("Execution:"); + console.log("Calling rebalance..."); + const tx = await vault.connect(signer).rebalance(); + await tx.wait(); + console.log("Tx", tx.hash); + + console.log("---------------------------------------------------------------"); + console.log("State after rebalance:"); + const drAfter = await stampl.deviationRatio.staticCall(); + console.log("System DR:", ethers.formatUnits(drAfter, drDecimals)); + console.log( + "Vault underlying balance:", + ethers.formatUnits(await vault.underlyingBalance(), underlyingDecimals), + ); + console.log( + "Vault perp balance:", + ethers.formatUnits(await vault.perpBalance(), perpDecimals), + ); + }); + +task("ops:drVaultDeposit", "Deposits underlying and perp tokens to DRBalancerVault") + .addParam( + "address", + "the address of the DRBalancerVault contract", + undefined, + types.string, + false, + ) + .addParam( + "underlyingAmount", + "the amount of underlying tokens (in float) to deposit", + undefined, + types.string, + false, + ) + .addParam( + "perpAmount", + "the amount of perp tokens (in float) to deposit", + undefined, + types.string, + false, + ) + .setAction(async function (args: TaskArguments, hre) { + const signer = (await hre.ethers.getSigners())[0]; + const signerAddress = await signer.getAddress(); + console.log("Signer", signerAddress); + + const { address, underlyingAmount, perpAmount } = args; + const vault = await hre.ethers.getContractAt("DRBalancerVault", address); + const underlying = await hre.ethers.getContractAt("ERC20", await vault.underlying()); + const perp = await hre.ethers.getContractAt("ERC20", await vault.perp()); + const underlyingDecimals = await underlying.decimals(); + const perpDecimals = await perp.decimals(); + const underlyingFixedPtAmount = ethers.parseUnits( + underlyingAmount, + underlyingDecimals, + ); + const perpFixedPtAmount = ethers.parseUnits(perpAmount, perpDecimals); + + console.log( + "Signer underlying balance", + ethers.formatUnits(await underlying.balanceOf(signerAddress), underlyingDecimals), + ); + console.log( + "Signer perp balance", + ethers.formatUnits(await perp.balanceOf(signerAddress), perpDecimals), + ); + + console.log("---------------------------------------------------------------"); + console.log("Preview deposit:"); + const [expectedNotes, expectedUnderlying, expectedPerp] = + await vault.computeMintAmt.staticCall(underlyingFixedPtAmount, perpFixedPtAmount); + console.log( + "Expected notes:", + ethers.formatUnits(expectedNotes, await vault.decimals()), + ); + console.log( + "Expected underlying in:", + ethers.formatUnits(expectedUnderlying, underlyingDecimals), + ); + console.log("Expected perp in:", ethers.formatUnits(expectedPerp, perpDecimals)); + + console.log("---------------------------------------------------------------"); + console.log("Execution:"); + console.log("Approving vault to spend tokens:"); + if ( + (await underlying.allowance(signerAddress, vault.target)) < underlyingFixedPtAmount + ) { + const tx1 = await underlying + .connect(signer) + .approve(vault.target, underlyingFixedPtAmount); + await tx1.wait(); + console.log("Tx", tx1.hash); + } + if ((await perp.allowance(signerAddress, vault.target)) < perpFixedPtAmount) { + const tx2 = await perp.connect(signer).approve(vault.target, perpFixedPtAmount); + await tx2.wait(); + console.log("Tx", tx2.hash); + } + + console.log("Deposit:"); + const tx3 = await vault + .connect(signer) + .deposit(underlyingFixedPtAmount, perpFixedPtAmount, 0); + await tx3.wait(); + console.log("Tx", tx3.hash); + + console.log("---------------------------------------------------------------"); + console.log( + "Signer vault notes balance", + ethers.formatUnits(await vault.balanceOf(signerAddress), await vault.decimals()), + ); + console.log( + "Signer underlying balance", + ethers.formatUnits(await underlying.balanceOf(signerAddress), underlyingDecimals), + ); + console.log( + "Signer perp balance", + ethers.formatUnits(await perp.balanceOf(signerAddress), perpDecimals), + ); + + console.log("---------------------------------------------------------------"); + console.log("Rebalance status:"); + const lastRebalance = await vault.lastRebalanceTimestampSec(); + const rebalanceFreq = await vault.rebalanceFreqSec(); + const nextRebalanceTime = Number(lastRebalance) + Number(rebalanceFreq); + const now = Math.floor(Date.now() / 1000); + const canRebalance = now >= nextRebalanceTime; + console.log( + "Can rebalance:", + canRebalance ? "yes" : `no (wait ${nextRebalanceTime - now}s)`, + ); + + try { + const [rebalanceAmt, isUnderlyingIntoPerp] = + await vault.computeRebalanceAmount.staticCall(); + console.log( + "Rebalance amount:", + ethers.formatUnits(rebalanceAmt, underlyingDecimals), + ); + console.log( + "Direction:", + isUnderlyingIntoPerp + ? "underlying -> perp (mint)" + : "perp -> underlying (redeem)", + ); + console.log("Rebalance pokable:", canRebalance && rebalanceAmt > 0n ? "yes" : "no"); + } catch (e) { + console.log("Unable to compute rebalance:", e.message); + } + }); diff --git a/spot-vaults/tasks/scripts/mainnet.sh b/spot-vaults/tasks/scripts/mainnet.sh index 9b0eb47f..05d7784b 100644 --- a/spot-vaults/tasks/scripts/mainnet.sh +++ b/spot-vaults/tasks/scripts/mainnet.sh @@ -24,6 +24,13 @@ yarn hardhat --network mainnet deploy:CharmManager \ --vault "0x2dcaff0f75765d7867887fc402b71c841b3a4bfb" \ --oracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" +yarn hardhat --network mainnet deploy:DRBalancerVault \ + --name "DR Balancer Vault" \ + --symbol "DR-VAULT" \ + --underlying "0xD46bA6D942050d489DBd938a2C909A5d5039A161" \ + --perp "0xC1f33e0cf7e40a67375007104B929E49a581bafE" \ + --rollover-vault "0x82A91a0D599A45d8E9Af781D67f695d7C72869Bd" + yarn hardhat --network mainnet transferOwnership "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" \ --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" @@ -33,11 +40,18 @@ yarn hardhat --network mainnet transferOwnership "0x574fca658b4B59E965C0e5f74761 yarn hardhat --network mainnet transferOwnership "0x2f67158859Fe0f69f5773570eC60444Fe0c1693c" \ --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" +yarn hardhat --network mainnet transferOwnership "0xd6e88D952ea0B1dFa42018c81eb597b3C1e2BF48" \ + --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" + +yarn hardhat --network mainnet transferOwnership "0x6f60625c5B4Bdf89b9F18B9c681310E6B3dAcDbD" \ + --new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662" + ######################################################################## ## INFO yarn hardhat --network mainnet info:MetaOracle "0x0f8f519878c10ce36C6aAF89c1AeefaaDE5D7881" yarn hardhat --network mainnet info:BillBroker "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" +yarn hardhat --network mainnet info:DRBalancerVault "0x6f60625c5B4Bdf89b9F18B9c681310E6B3dAcDbD" yarn hardhat --network mainnet info:WethWamplManager "0x574fca658b4B59E965C0e5f74761AE0Ac41DA6a7" yarn hardhat --network mainnet info:UsdcSpotManager "0x2f67158859Fe0f69f5773570eC60444Fe0c1693c" @@ -61,6 +75,14 @@ yarn hardhat --network mainnet ops:redeem \ --address "0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB" \ --amount 1000 +yarn hardhat --network mainnet ops:drVaultDeposit \ + --address "" \ + --underlying-amount 1000 \ + --perp-amount 1000 + +yarn hardhat --network mainnet ops:drVaultRebalance \ + --address "" + ######################################################################## ## Upgrade diff --git a/spot-vaults/tasks/scripts/sepolia.sh b/spot-vaults/tasks/scripts/sepolia.sh index 86ac002e..5cac919d 100644 --- a/spot-vaults/tasks/scripts/sepolia.sh +++ b/spot-vaults/tasks/scripts/sepolia.sh @@ -15,10 +15,18 @@ yarn hardhat --network sepolia deploy:BillBroker \ --perp "0xdcCef9065876fD654bAddeBAa778FDA43E0bfC1F" \ --pricing-strategy "0x08c5b39F000705ebeC8427C1d64D6262392944EE" +yarn hardhat --network sepolia deploy:DRBalancerVault \ + --name "DR Balancer Vault" \ + --symbol "DR-VAULT" \ + --underlying "0x251410f849ad67bebffdb5a549e5f02d5d9c25ba" \ + --perp "0xdcCef9065876fD654bAddeBAa778FDA43E0bfC1F" \ + --rollover-vault "0x107614c6602A8e602952Da107B8fE62b5Ab13b04" + ######################################################################## ## INFO yarn hardhat --network sepolia info:BillBroker "0xc3f6D1F1d253EdC8B34D78Bc6cDD2b3eEFAd76BD" +yarn hardhat --network sepolia info:DRBalancerVault "0xB02114487836409136B0006A090995D63931C486" ######################################################################## ## OPS @@ -46,4 +54,12 @@ yarn hardhat --network sepolia ops:swapPerpsForUSD \ yarn hardhat --network sepolia ops:redeem \ --address "0xc3f6D1F1d253EdC8B34D78Bc6cDD2b3eEFAd76BD" \ - --amount 1000 \ No newline at end of file + --amount 1000 + +yarn hardhat --network sepolia ops:drVaultDeposit \ + --address "0xB02114487836409136B0006A090995D63931C486" \ + --underlying-amount 1000 \ + --perp-amount 1000 + +yarn hardhat --network sepolia ops:drVaultRebalance \ + --address "0xB02114487836409136B0006A090995D63931C486" \ No newline at end of file