diff --git a/abi/TokenDistributor.json b/abi/TokenDistributor.json index c34f41a..b0b20e4 100644 --- a/abi/TokenDistributor.json +++ b/abi/TokenDistributor.json @@ -218,6 +218,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint208", + "name": "newTDV", + "type": "uint208" + } + ], + "name": "migrateDropTokensAndTDV", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -281,6 +304,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint208", + "name": "newTDV", + "type": "uint208" + } + ], + "name": "setTDV", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "token", diff --git a/abi/Vault.json b/abi/Vault.json index 7b9b514..e9b43c4 100644 --- a/abi/Vault.json +++ b/abi/Vault.json @@ -1131,6 +1131,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "upgradeCallBack", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/ignition/deployments/chain-8453/deployed_addresses.json b/ignition/deployments/chain-8453/deployed_addresses.json index 886bd3f..0da9797 100644 --- a/ignition/deployments/chain-8453/deployed_addresses.json +++ b/ignition/deployments/chain-8453/deployed_addresses.json @@ -23,11 +23,9 @@ "Main#InputModifierLib": "0x47F8FB8136BFAFb9791D4C0CBf8e0764b02D619e", "Main#VaultInitLib": "0x262166E3d46dA3a796BF7BE448bdddfd11FFB56f", "Main#VaultDepositLib": "0x60d879820974964b793B60a9FA14103B7f9527B0", - "Main#VaultSpendLib": "0x421DA02Cb0C0f457F96abF719A48ef61E78c3376", - "Main#VaultImplementation": "0xA92aA9b65d2D5b6C9a5Af2C4365357A304FC247B", + "Main#VaultSpendLib": "0x94CE27CDFD55208678FB250FeD21B7f1FfdEc4Ff", + "Main#VaultImplementation": "0xF136A71D02675DC797863DBab7fB4E30b63d7680", "Main#VaultProxy": "0xE0Eefe4AA0cB32740aDFD8083AbeC255AaC3b379", "Main#Vault": "0xE0Eefe4AA0cB32740aDFD8083AbeC255AaC3b379", - "Main#ProtocolManager": "0xCC499487F6a1780dB9410a65408B98E63346aCfe", - "VaultUpgradeProd#VaultSpendLib": "0x94CE27CDFD55208678FB250FeD21B7f1FfdEc4Ff", - "VaultUpgradeProd#VaultImplementation": "0x5Bb28C730A85D2C5Ea834592b6D06a444D607AB7" + "Main#ProtocolManager": "0xCC499487F6a1780dB9410a65408B98E63346aCfe" } diff --git a/ignition/modules/VaultUpgrade.module.ts b/ignition/modules/VaultUpgrade.module.ts index e276f69..5c4c91e 100644 --- a/ignition/modules/VaultUpgrade.module.ts +++ b/ignition/modules/VaultUpgrade.module.ts @@ -1,10 +1,7 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; -export default buildModule("VaultUpgradeProd", (m) => { +export default buildModule("VaultUpgrade", (m) => { const interestLib = m.contractAt("InterestLib", "0xe8426F0675C9Da7340b4E8801cDE6a5C59f23Eb7"); - const vaultMathLib = m.contractAt("VaultMathLib", "0x67bCC483fAaD61c3B7eBAdb31c884b8Aba9A13Ff"); - - const inputsLib = m.contractAt("InputsLib", "0x8B77b2Bf6A592361aF18803d785c25a1BBE1104c"); const investmentVaultLib = m.contractAt("InvestmentVaultLib", "0x3B0775204AF03c2E9940CfbCB9fbeA0949CadA7B"); @@ -12,16 +9,7 @@ export default buildModule("VaultUpgradeProd", (m) => { const vaultDepositLib = m.contractAt("VaultDepositLib", "0x60d879820974964b793B60a9FA14103B7f9527B0"); - const vaultSpendLib = m.library("VaultSpendLib", { - id: `VaultSpendLib_1`, - libraries: { - VaultMathLib: vaultMathLib, - InterestLib: interestLib, - InvestmentVaultLib: investmentVaultLib, - InputsLib: inputsLib, - }, - after: [vaultDepositLib], - }); + const vaultSpendLib = m.contractAt("VaultSpendLib", "0x94CE27CDFD55208678FB250FeD21B7f1FfdEc4Ff"); const vaultInitLib = m.contractAt("VaultInitLib", "0x262166E3d46dA3a796BF7BE448bdddfd11FFB56f"); @@ -34,8 +22,7 @@ export default buildModule("VaultUpgradeProd", (m) => { VaultSpendLib: vaultSpendLib, InterestLib: interestLib, }, - id: `Vault_1`, - after: [vaultSpendLib], + id: `Vault_5`, }); return { diff --git a/scripts/encodeUpgradeCallBack.ts b/scripts/encodeUpgradeCallBack.ts index fdf7ee0..d3f4ecd 100644 --- a/scripts/encodeUpgradeCallBack.ts +++ b/scripts/encodeUpgradeCallBack.ts @@ -5,7 +5,8 @@ const encodeUpgradeCallBack = () => { // encode call upgradeCallBack const vaultInterface = new hre.ethers.Interface(vaultAbi); const callData = vaultInterface.encodeFunctionData("upgradeCallBack", []); - console.log(callData); + const hash = hre.ethers.keccak256(callData); + console.log(`callData: ${callData}, hash: ${hash}`); }; encodeUpgradeCallBack(); diff --git a/src/token/Token.sol b/src/token/Token.sol index e0a59d0..1bc6833 100644 --- a/src/token/Token.sol +++ b/src/token/Token.sol @@ -17,9 +17,9 @@ contract Token is ERC20Capped, ERC20Permit, Ownable { * @dev The token is capped at 3,000,000 ZRL */ constructor() - ERC20("Zeroldger Token", "ZRL") + ERC20("ZeroLedger Token", "ZRL") ERC20Capped(30_000_000 * 10 ** 18) - ERC20Permit("ZRL") + ERC20Permit("ZeroLedger Token") Ownable(msg.sender) {} diff --git a/src/token/TokenDistributor.sol b/src/token/TokenDistributor.sol index 61a0700..23bc06c 100644 --- a/src/token/TokenDistributor.sol +++ b/src/token/TokenDistributor.sol @@ -25,7 +25,7 @@ struct MintingLayer { contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { using Math for uint256; - /// @notice Address of the anchor token that this distributor distributes. + /// @notice Address of the anchor token that this distributor uses for TDV computation. address public accountingToken; /// @notice Address of the ZRL token that this distributor mints. address public token; @@ -59,8 +59,7 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { mintingLayers[3] = MintingLayer(3_750_000, 175 * 10 ** (LAYER_DECIMALS - 2)); // 1.75 mintingLayers[4] = MintingLayer(7_750_000, 75 * 10 ** (LAYER_DECIMALS - 2)); // 0.75 mintingLayers[5] = MintingLayer(15_750_000, 3125 * 10 ** (LAYER_DECIMALS - 4)); // 0.3125 - mintingLayers[6] = MintingLayer(31_750_000, 125 * 10 ** (LAYER_DECIMALS - 3)); // 0.125 ZRL per 1 USDC (tokenomics - // table round 7) + mintingLayers[6] = MintingLayer(31_750_000, 125 * 10 ** (LAYER_DECIMALS - 3)); // 0.125 mintingLayers[7] = MintingLayer(63_750_000, 46875 * 10 ** (LAYER_DECIMALS - 6)); // 0.046875 mintingLayers[8] = MintingLayer(127_750_000, 15625 * 10 ** (LAYER_DECIMALS - 6)); // 0.015625 mintingLayers[9] = MintingLayer(255_750_000, 390625); // 0.00390625 @@ -69,6 +68,10 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { accountingToken = anchorToken_; } + function setTDV(uint208 newTDV) public onlyOwner { + TDV = newTDV; + } + /// @inheritdoc ITokenDistributor function distribute(address to, uint208 anchorAmount) external onlyOwner { (uint256 toMint, uint208 newTDV) = _compute(TDV, anchorAmount); @@ -78,7 +81,7 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { /// @inheritdoc ITokenDistributor function previewDistribute(uint208 anchorAmount) external view returns (uint256 toMint) { - (toMint,) = _compute(TDV, anchorAmount); + (toMint, ) = _compute(TDV, anchorAmount); } /** @@ -99,8 +102,11 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { uint208 leftTDVInLayer = uint208(mintingLayers[layer].TDVLayerCap * 10 ** anchorDecimals) - newTDV; if (anchorAmountToProcess > leftTDVInLayer) { - toMintAcc += - (leftTDVInLayer * anchorToTokenPow).mulDiv(mintingLayers[layer].multiplier, LAYER_POW, Math.Rounding.Floor); + toMintAcc += (leftTDVInLayer * anchorToTokenPow).mulDiv( + mintingLayers[layer].multiplier, + LAYER_POW, + Math.Rounding.Floor + ); layer = ++layer; anchorAmountToProcess -= leftTDVInLayer; newTDV = newTDV + leftTDVInLayer; @@ -108,7 +114,9 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { // base formula: anchorAmount * layer_multiplier // with decimals: anchorAmount * 10 ** (token_decimals - decimals) * layer_multiplier / 10 ** LAYER_DECIMALS toMintAcc += (uint256(anchorAmountToProcess) * anchorToTokenPow).mulDiv( - mintingLayers[layer].multiplier, LAYER_POW, Math.Rounding.Floor + mintingLayers[layer].multiplier, + LAYER_POW, + Math.Rounding.Floor ); newTDV = newTDV + anchorAmountToProcess; anchorAmountToProcess = 0; @@ -153,13 +161,26 @@ contract TokenDistributor is ITokenDistributor, Ownable, ReentrancyGuard { } /// @inheritdoc ITokenDistributor - function claim(bytes32[] calldata proof, uint256 amount) - external - nonReentrant - onlyNotClaimed(msg.sender) - onlyValidProof(msg.sender, amount, proof) - { + function claim( + bytes32[] calldata proof, + uint256 amount + ) external nonReentrant onlyNotClaimed(msg.sender) onlyValidProof(msg.sender, amount, proof) { claimed[msg.sender] = true; Token(token).mint(msg.sender, amount); } + + function migrateDropTokensAndTDV( + address[] calldata accounts, + uint256[] calldata amounts, + uint208 newTDV + ) external onlyOwner { + if (TDV != 0) { + revert("migrated"); + } + TDV = newTDV; + for (uint256 i = 0; i < accounts.length; i++) { + claimed[accounts[i]] = true; + Token(token).mint(accounts[i], amounts[i]); + } + } } diff --git a/src/vault/Vault.sol b/src/vault/Vault.sol index 1870273..cdf624c 100644 --- a/src/vault/Vault.sol +++ b/src/vault/Vault.sol @@ -31,8 +31,8 @@ import {State} from "src/vault/VaultStorage.sol"; /** * @title Vault - * @notice The main Zeroledger contract and entry point for the protocol. - * @dev Zeroldger token & token distributor are immutable and cannot be upgraded. + * @notice The main ZeroLedger contract and entry point for the protocol. + * @dev ZeroLedger token & token distributor are immutable and cannot be upgraded. * @author ZeroLedger */ contract Vault is @@ -81,6 +81,8 @@ contract Vault is ); } + function upgradeCallBack() external reinitializer(4) {} + /// @inheritdoc IVault function approveUpgrade(address newImplementation, bytes32 paramsHash) external restricted { _getStorage().approvedImplementation = newImplementation; @@ -104,6 +106,7 @@ contract Vault is */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable override onlyProxy { State storage state = _getStorage(); + require(state.approvedImplementation != address(0), "impl not approved"); require(state.approvedImplementation == newImplementation, "impl not approved"); require(keccak256(data) == state.approvedUpgradeParamsHash, "params not approved"); // clear to prevent reuse