From ad3283688e1b9add20495b47210f9f2531a92ec3 Mon Sep 17 00:00:00 2001 From: cyc60 Date: Fri, 12 Sep 2025 10:01:28 +0300 Subject: [PATCH 1/2] Funding validators --- pyproject.toml | 2 +- src/common/abi/IEthVault.json | 1897 ++++++++++++++++++++++++++ src/common/contracts.py | 26 +- src/validators/endpoints.py | 49 +- src/validators/schema.py | 17 + src/validators/typings.py | 4 +- src/validators/validators.py | 29 +- src/validators/validators_manager.py | 34 +- 8 files changed, 2041 insertions(+), 17 deletions(-) create mode 100644 src/common/abi/IEthVault.json diff --git a/pyproject.toml b/pyproject.toml index ac7c75d..b3e425e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,6 +105,6 @@ exclude = ''' [tool.vulture] ignore_names = [ "app_instance", - "register_validators", "get_info" # used in API routes + "register_validators", "fund_validators", "get_info" # used in API routes ] ignore_decorators = ["@router"] diff --git a/src/common/abi/IEthVault.json b/src/common/abi/IEthVault.json new file mode 100644 index 0000000..e41d0af --- /dev/null +++ b/src/common/abi/IEthVault.json @@ -0,0 +1,1897 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "args", + "type": "tuple", + "internalType": "struct IEthVault.EthVaultConstructorArgs", + "components": [ + { + "name": "keeper", + "type": "address", + "internalType": "address" + }, + { + "name": "vaultsRegistry", + "type": "address", + "internalType": "address" + }, + { + "name": "validatorsRegistry", + "type": "address", + "internalType": "address" + }, + { + "name": "validatorsWithdrawals", + "type": "address", + "internalType": "address" + }, + { + "name": "validatorsConsolidations", + "type": "address", + "internalType": "address" + }, + { + "name": "consolidationsChecker", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenVaultController", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenConfig", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenVaultEscrow", + "type": "address", + "internalType": "address" + }, + { + "name": "sharedMevEscrow", + "type": "address", + "internalType": "address" + }, + { + "name": "depositDataRegistry", + "type": "address", + "internalType": "address" + }, + { + "name": "exitingAssetsClaimDelay", + "type": "uint64", + "internalType": "uint64" + } + ] + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "admin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burnOsToken", + "inputs": [ + { + "name": "osTokenShares", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "calculateExitedAssets", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "positionTicket", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exitQueueIndex", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "leftTickets", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exitedTickets", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exitedAssets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "capacity", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "claimExitedAssets", + "inputs": [ + { + "name": "positionTicket", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exitQueueIndex", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "consolidateValidators", + "inputs": [ + { + "name": "validators", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validatorsManagerSignature", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "oracleSignatures", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "convertToAssets", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToShares", + "inputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deposit", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "referrer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "depositAndMintOsToken", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "referrer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "donateAssets", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "enterExitQueue", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "positionTicket", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "feePercent", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint16", + "internalType": "uint16" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "feeRecipient", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "fundValidators", + "inputs": [ + { + "name": "validators", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validatorsManagerSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getExitQueueData", + "inputs": [], + "outputs": [ + { + "name": "queuedShares", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "unclaimedAssets", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalExitingTickets", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalExitingAssets", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalTickets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getExitQueueIndex", + "inputs": [ + { + "name": "positionTicket", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "int256", + "internalType": "int256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getShares", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "implementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "params", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "isStateUpdateRequired", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "liquidateOsToken", + "inputs": [ + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mevEscrow", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mintOsToken", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "referrer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "multicall", + "inputs": [ + { + "name": "data", + "type": "bytes[]", + "internalType": "bytes[]" + } + ], + "outputs": [ + { + "name": "results", + "type": "bytes[]", + "internalType": "bytes[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "osTokenPositions", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "shares", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "receiveFromMevEscrow", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "redeemOsToken", + "inputs": [ + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "registerValidators", + "inputs": [ + { + "name": "keeperParams", + "type": "tuple", + "internalType": "struct IKeeperValidators.ApprovalParams", + "components": [ + { + "name": "validatorsRegistryRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validators", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signatures", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "exitSignaturesIpfsHash", + "type": "string", + "internalType": "string" + } + ] + }, + { + "name": "validatorsManagerSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAdmin", + "inputs": [ + { + "name": "newAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFeePercent", + "inputs": [ + { + "name": "_feePercent", + "type": "uint16", + "internalType": "uint16" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFeeRecipient", + "inputs": [ + { + "name": "_feeRecipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setMetadata", + "inputs": [ + { + "name": "metadataIpfsHash", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setValidatorsManager", + "inputs": [ + { + "name": "validatorsManager_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "totalAssets", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalShares", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOsTokenPositionToEscrow", + "inputs": [ + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "positionTicket", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateState", + "inputs": [ + { + "name": "harvestParams", + "type": "tuple", + "internalType": "struct IKeeperRewards.HarvestParams", + "components": [ + { + "name": "rewardsRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "reward", + "type": "int160", + "internalType": "int160" + }, + { + "name": "unlockedMevReward", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "proof", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateStateAndDeposit", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "referrer", + "type": "address", + "internalType": "address" + }, + { + "name": "harvestParams", + "type": "tuple", + "internalType": "struct IKeeperRewards.HarvestParams", + "components": [ + { + "name": "rewardsRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "reward", + "type": "int160", + "internalType": "int160" + }, + { + "name": "unlockedMevReward", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "proof", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "outputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "updateStateAndDepositAndMintOsToken", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "osTokenShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "referrer", + "type": "address", + "internalType": "address" + }, + { + "name": "harvestParams", + "type": "tuple", + "internalType": "struct IKeeperRewards.HarvestParams", + "components": [ + { + "name": "rewardsRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "reward", + "type": "int160", + "internalType": "int160" + }, + { + "name": "unlockedMevReward", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "proof", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "v2Validators", + "inputs": [ + { + "name": "publicKeyHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "isRegistered", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "validatorsManager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "validatorsManagerNonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "vaultId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "withdrawValidators", + "inputs": [ + { + "name": "validators", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "validatorsManagerSignature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "withdrawableAssets", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "AdminUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newAdmin", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AssetsDonated", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CheckpointCreated", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Deposited", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "referrer", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExitQueueEntered", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "positionTicket", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExitedAssetsClaimed", + "inputs": [ + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "prevPositionTicket", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newPositionTicket", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "withdrawnAssets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExitingAssetsPenalized", + "inputs": [ + { + "name": "penalty", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeePercentUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "feePercent", + "type": "uint16", + "indexed": false, + "internalType": "uint16" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeeRecipientUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "feeRecipient", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeeSharesMinted", + "inputs": [ + { + "name": "receiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "KeysManagerUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "keysManager", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MetadataUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "metadataIpfsHash", + "type": "string", + "indexed": false, + "internalType": "string" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OsTokenBurned", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OsTokenLiquidated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "osTokenShares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "receivedAssets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OsTokenMinted", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "referrer", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OsTokenRedeemed", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "osTokenShares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Redeemed", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "V2ExitQueueEntered", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "positionTicket", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "shares", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "assets", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "V2ValidatorRegistered", + "inputs": [ + { + "name": "publicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorConsolidationSubmitted", + "inputs": [ + { + "name": "fromPublicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "toPublicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "feePaid", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorFunded", + "inputs": [ + { + "name": "publicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorRegistered", + "inputs": [ + { + "name": "publicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorWithdrawalSubmitted", + "inputs": [ + { + "name": "publicKey", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "feePaid", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorsManagerUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "validatorsManager", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorsRootUpdated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "validatorsRoot", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessDenied", + "inputs": [] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "CapacityExceeded", + "inputs": [] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, + { + "type": "error", + "name": "ExitRequestNotProcessed", + "inputs": [] + }, + { + "type": "error", + "name": "FailedCall", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientBalance", + "inputs": [ + { + "name": "balance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "needed", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAssets", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCapacity", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCheckpointValue", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidFeePercent", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidFeeRecipient", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInitialization", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidPosition", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSecurityDeposit", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidShares", + "inputs": [] + }, + { + "type": "error", + "name": "LowLtv", + "inputs": [] + }, + { + "type": "error", + "name": "NotCollateralized", + "inputs": [] + }, + { + "type": "error", + "name": "NotHarvested", + "inputs": [] + }, + { + "type": "error", + "name": "NotInitializing", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "TooEarlyUpdate", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "UpgradeFailed", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/src/common/contracts.py b/src/common/contracts.py index 2cc49f5..3401616 100644 --- a/src/common/contracts.py +++ b/src/common/contracts.py @@ -14,17 +14,21 @@ class ContractWrapper: abi_path: str = '' + settings_key: str = '' + + def __init__(self, address: ChecksumAddress | None = None): + self.address = address + + @property + def contract_address(self) -> ChecksumAddress: + return self.address or getattr(settings.network_config, self.settings_key) @cached_property def contract(self) -> AsyncContract: current_dir = os.path.dirname(__file__) with open(os.path.join(current_dir, self.abi_path), encoding='utf-8') as f: abi = json.load(f) - return execution_client.eth.contract(abi=abi, address=self.address) - - @property - def address(self) -> ChecksumAddress: - raise NotImplementedError + return execution_client.eth.contract(abi=abi, address=self.contract_address) @property def functions(self) -> AsyncContractFunctions: @@ -40,14 +44,18 @@ def encode_abi(self, fn_name: str, args: list | None = None) -> HexStr: class ValidatorsRegistryContract(ContractWrapper): abi_path = 'abi/IValidatorsRegistry.json' - - @property - def address(self) -> ChecksumAddress: - return settings.network_config.VALIDATORS_REGISTRY_CONTRACT_ADDRESS + settings_key = 'VALIDATORS_REGISTRY_CONTRACT_ADDRESS' async def get_registry_root(self) -> Bytes32: """Fetches the latest validators registry root.""" return await self.contract.functions.get_deposit_root().call() +class VaultContract(ContractWrapper): + abi_path = 'abi/IEthVault.json' + + async def validators_manager_nonce(self) -> int: + return await self.contract.functions.validatorsManagerNonce().call() + + validators_registry_contract = ValidatorsRegistryContract() diff --git a/src/validators/endpoints.py b/src/validators/endpoints.py index c2730f7..0bfdcec 100644 --- a/src/validators/endpoints.py +++ b/src/validators/endpoints.py @@ -2,13 +2,17 @@ from web3 import Web3 from src.common.app_state import AppState -from src.common.contracts import validators_registry_contract +from src.common.contracts import VaultContract, validators_registry_contract from src.validators import schema from src.validators.validators import ( generate_validators_from_keystore, generate_validators_in_place, + get_validators_for_funding, +) +from src.validators.validators_manager import ( + get_validators_manager_signature_with_nonce, + get_validators_manager_signature_with_registry_root, ) -from src.validators.validators_manager import get_validators_manager_signature router = APIRouter() @@ -47,7 +51,7 @@ async def register_validators( validators_registry_root = await validators_registry_contract.get_registry_root() - validators_manager_signature = get_validators_manager_signature( + validators_manager_signature = get_validators_manager_signature_with_registry_root( Web3.to_checksum_address(request.vault), Web3.to_hex(validators_registry_root), validators, @@ -57,3 +61,42 @@ async def register_validators( validators=validator_items, validators_manager_signature=validators_manager_signature, ) + + +@router.post('/fund') +async def fund_validators( + request: schema.ValidatorsFundRequest, +) -> schema.ValidatorsFundResponse: + validator_items = [] + app_state = AppState() + if not app_state.keystore: + raise ValueError('Keystore is required for funding validators') + + validators = get_validators_for_funding( + keystore=app_state.keystore, + vault_address=request.vault, + public_keys=request.public_keys, + amounts=request.amounts, + ) + + for validator in validators: + validator_items.append( + schema.ValidatorsFundResponseItem( + public_key=validator.public_key, + deposit_signature=validator.deposit_signature, + amount=validator.amount, + ) + ) + + vault_contact = VaultContract(request.vault) + validators_manager_nonce = await vault_contact.validators_manager_nonce() + validators_manager_signature = get_validators_manager_signature_with_nonce( + Web3.to_checksum_address(request.vault), + validators_manager_nonce, + validators, + ) + + return schema.ValidatorsFundResponse( + validators=validator_items, + validators_manager_signature=validators_manager_signature, + ) diff --git a/src/validators/schema.py b/src/validators/schema.py index 526e716..5e17be6 100644 --- a/src/validators/schema.py +++ b/src/validators/schema.py @@ -22,3 +22,20 @@ class ValidatorsRegisterResponseItem(BaseModel): class ValidatorsRegisterResponse(BaseModel): validators: list[ValidatorsRegisterResponseItem] validators_manager_signature: HexStr + + +class ValidatorsFundRequest(BaseModel): + vault: ChecksumAddress + public_keys: list[HexStr] + amounts: list[Gwei] + + +class ValidatorsFundResponseItem(BaseModel): + public_key: HexStr + deposit_signature: HexStr + amount: Gwei + + +class ValidatorsFundResponse(BaseModel): + validators: list[ValidatorsFundResponseItem] + validators_manager_signature: HexStr diff --git a/src/validators/typings.py b/src/validators/typings.py index 749de77..56d0a01 100644 --- a/src/validators/typings.py +++ b/src/validators/typings.py @@ -19,5 +19,5 @@ class Validator: deposit_data_root: HexStr deposit_signature: HexStr amount: Gwei - exit_signature: BLSSignature - validator_type: ValidatorType + validator_type: ValidatorType = ValidatorType.V2 + exit_signature: BLSSignature | None = None diff --git a/src/validators/validators.py b/src/validators/validators.py index 1596160..56f820f 100644 --- a/src/validators/validators.py +++ b/src/validators/validators.py @@ -1,7 +1,7 @@ import secrets import milagro_bls_binding as bls -from eth_typing import BLSPrivateKey, BLSSignature, ChecksumAddress +from eth_typing import BLSPrivateKey, BLSSignature, ChecksumAddress, HexStr from py_ecc.optimized_bls12_381.optimized_curve import curve_order from sw_utils import ConsensusFork, get_exit_message_signing_root from web3 import Web3 @@ -93,6 +93,33 @@ def generate_validators_from_keystore( return validators +def get_validators_for_funding( + keystore: LocalKeystore, + vault_address: ChecksumAddress, + public_keys: list[HexStr], + amounts: list[Gwei], +) -> list[Validator]: + validators = [] + for public_key, amount in zip(public_keys, amounts): + if public_key not in keystore: + raise RuntimeError(f'Public key {public_key} not found in keystores') + deposit_data = keystore.get_deposit_data( + public_key=public_key, + amount=amount, + vault_address=vault_address, + validator_type=ValidatorType.V2, + ) + validators.append( + Validator( + public_key=Web3.to_hex(deposit_data['pubkey']), + deposit_signature=Web3.to_hex(deposit_data['signature']), + amount=amount, + deposit_data_root=Web3.to_hex(deposit_data['deposit_data_root']), + ) + ) + return validators + + def _get_exit_signature( validator_index: int, private_key: BLSPrivateKey, fork: ConsensusFork | None = None ) -> BLSSignature: diff --git a/src/validators/validators_manager.py b/src/validators/validators_manager.py index e2b2619..bad6d7b 100644 --- a/src/validators/validators_manager.py +++ b/src/validators/validators_manager.py @@ -29,7 +29,7 @@ def load_validators_manager_account() -> LocalAccount: return Account().from_key(key) -def get_validators_manager_signature( +def get_validators_manager_signature_with_registry_root( vault: ChecksumAddress, validators_registry_root: HexStr, validators: Sequence[Validator] ) -> HexStr: encoded_validators = [_encode_validator(v) for v in validators] @@ -61,6 +61,38 @@ def get_validators_manager_signature( return HexStr(signed_msg.signature.hex()) +def get_validators_manager_signature_with_nonce( + vault: ChecksumAddress, validators_manager_nonce: int, validators: Sequence[Validator] +) -> HexStr: + encoded_validators = [_encode_validator(v) for v in validators] + + full_message = { + 'primaryType': 'VaultValidators', + 'types': { + 'VaultValidators': [ + {'name': 'validatorsRegistryRoot', 'type': 'bytes32'}, + {'name': 'validators', 'type': 'bytes'}, + ], + }, + 'domain': { + 'name': 'VaultValidators', + 'version': '1', + 'chainId': settings.network_config.CHAIN_ID, + 'verifyingContract': vault, + }, + 'message': { + 'validatorsRegistryRoot': validators_manager_nonce.to_bytes(32, byteorder='big'), + 'validators': b''.join(encoded_validators), + }, + } + + app_state = AppState() + encoded_message = encode_typed_data(full_message=full_message) + signed_msg = app_state.validators_manager_account.sign_message(encoded_message) + + return HexStr(signed_msg.signature.hex()) + + def _encode_validator(v: Validator) -> bytes: encoded_validator = [ Web3.to_bytes(hexstr=v.public_key), From 4c6174210158cf89daa9e6b6b36acfbaf6cc21ea Mon Sep 17 00:00:00 2001 From: cyc60 Date: Fri, 12 Sep 2025 14:31:40 +0300 Subject: [PATCH 2/2] Add withdrawals and consolidations --- pyproject.toml | 4 +- src/validators/endpoints.py | 46 ++++++++++- src/validators/schema.py | 16 ++++ src/validators/validators_manager.py | 118 +++++++++++++++++---------- 4 files changed, 138 insertions(+), 46 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b3e425e..809b2d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,6 +105,8 @@ exclude = ''' [tool.vulture] ignore_names = [ "app_instance", - "register_validators", "fund_validators", "get_info" # used in API routes + "register_validators", "fund_validators", # used in API routes + "withdraw_validators", "consolidate_validators", # used in API routes + "get_info" # used in API routes ] ignore_decorators = ["@router"] diff --git a/src/validators/endpoints.py b/src/validators/endpoints.py index 0bfdcec..1340ddf 100644 --- a/src/validators/endpoints.py +++ b/src/validators/endpoints.py @@ -10,8 +10,10 @@ get_validators_for_funding, ) from src.validators.validators_manager import ( - get_validators_manager_signature_with_nonce, - get_validators_manager_signature_with_registry_root, + get_validators_manager_signature_consolidation, + get_validators_manager_signature_funding, + get_validators_manager_signature_register, + get_validators_manager_signature_withdrawal, ) router = APIRouter() @@ -51,7 +53,7 @@ async def register_validators( validators_registry_root = await validators_registry_contract.get_registry_root() - validators_manager_signature = get_validators_manager_signature_with_registry_root( + validators_manager_signature = get_validators_manager_signature_register( Web3.to_checksum_address(request.vault), Web3.to_hex(validators_registry_root), validators, @@ -90,7 +92,7 @@ async def fund_validators( vault_contact = VaultContract(request.vault) validators_manager_nonce = await vault_contact.validators_manager_nonce() - validators_manager_signature = get_validators_manager_signature_with_nonce( + validators_manager_signature = get_validators_manager_signature_funding( Web3.to_checksum_address(request.vault), validators_manager_nonce, validators, @@ -100,3 +102,39 @@ async def fund_validators( validators=validator_items, validators_manager_signature=validators_manager_signature, ) + + +@router.post('/withdraw') +async def withdraw_validators( + request: schema.ValidatorsWithdrawalRequest, +) -> schema.ValidatorsSignatureResponse: + vault_contact = VaultContract(request.vault) + validators_manager_nonce = await vault_contact.validators_manager_nonce() + validators_manager_signature = get_validators_manager_signature_withdrawal( + Web3.to_checksum_address(request.vault), + validators_manager_nonce, + request.public_keys, + request.amounts, + ) + + return schema.ValidatorsSignatureResponse( + validators_manager_signature=validators_manager_signature, + ) + + +@router.post('/consolidate') +async def consolidate_validators( + request: schema.ValidatorsConsolidationRequest, +) -> schema.ValidatorsSignatureResponse: + vault_contact = VaultContract(request.vault) + validators_manager_nonce = await vault_contact.validators_manager_nonce() + validators_manager_signature = get_validators_manager_signature_consolidation( + Web3.to_checksum_address(request.vault), + validators_manager_nonce, + request.source_public_keys, + request.target_public_keys, + ) + + return schema.ValidatorsSignatureResponse( + validators_manager_signature=validators_manager_signature, + ) diff --git a/src/validators/schema.py b/src/validators/schema.py index 5e17be6..00d34b5 100644 --- a/src/validators/schema.py +++ b/src/validators/schema.py @@ -39,3 +39,19 @@ class ValidatorsFundResponseItem(BaseModel): class ValidatorsFundResponse(BaseModel): validators: list[ValidatorsFundResponseItem] validators_manager_signature: HexStr + + +class ValidatorsWithdrawalRequest(BaseModel): + vault: ChecksumAddress + public_keys: list[HexStr] + amounts: list[Gwei] + + +class ValidatorsConsolidationRequest(BaseModel): + vault: ChecksumAddress + source_public_keys: list[HexStr] + target_public_keys: list[HexStr] + + +class ValidatorsSignatureResponse(BaseModel): + validators_manager_signature: HexStr diff --git a/src/validators/validators_manager.py b/src/validators/validators_manager.py index bad6d7b..8bee1f4 100644 --- a/src/validators/validators_manager.py +++ b/src/validators/validators_manager.py @@ -7,6 +7,7 @@ from eth_account.signers.local import LocalAccount from eth_typing import ChecksumAddress, HexStr from web3 import Web3 +from web3.types import Gwei from src.common.app_state import AppState from src.config import settings @@ -29,43 +30,89 @@ def load_validators_manager_account() -> LocalAccount: return Account().from_key(key) -def get_validators_manager_signature_with_registry_root( +def get_validators_manager_signature_register( vault: ChecksumAddress, validators_registry_root: HexStr, validators: Sequence[Validator] ) -> HexStr: encoded_validators = [_encode_validator(v) for v in validators] + return _create_and_sign_message( + vault=vault, + validators=b''.join(encoded_validators), + validators_registry_root=Web3.to_bytes(hexstr=validators_registry_root), + ) - full_message = { - 'primaryType': 'VaultValidators', - 'types': { - 'VaultValidators': [ - {'name': 'validatorsRegistryRoot', 'type': 'bytes32'}, - {'name': 'validators', 'type': 'bytes'}, - ], - }, - 'domain': { - 'name': 'VaultValidators', - 'version': '1', - 'chainId': settings.network_config.CHAIN_ID, - 'verifyingContract': vault, - }, - 'message': { - 'validatorsRegistryRoot': Web3.to_bytes(hexstr=validators_registry_root), - 'validators': b''.join(encoded_validators), - }, - } - - app_state = AppState() - encoded_message = encode_typed_data(full_message=full_message) - signed_msg = app_state.validators_manager_account.sign_message(encoded_message) - return HexStr(signed_msg.signature.hex()) - - -def get_validators_manager_signature_with_nonce( +def get_validators_manager_signature_funding( vault: ChecksumAddress, validators_manager_nonce: int, validators: Sequence[Validator] ) -> HexStr: encoded_validators = [_encode_validator(v) for v in validators] + return _create_and_sign_message( + vault=vault, + validators=b''.join(encoded_validators), + validators_registry_root=validators_manager_nonce.to_bytes(32, byteorder='big'), + ) + + +def get_validators_manager_signature_withdrawal( + vault: ChecksumAddress, + validators_manager_nonce: int, + public_keys: list[HexStr], + amounts: list[Gwei], +) -> HexStr: + encoded_withdrawals = _encode_withdrawals(public_keys, amounts) + return _create_and_sign_message( + vault=vault, + validators=encoded_withdrawals, + validators_registry_root=validators_manager_nonce.to_bytes(32, byteorder='big'), + ) + + +def get_validators_manager_signature_consolidation( + vault: ChecksumAddress, + validators_manager_nonce: int, + source_public_keys: list[HexStr], + target_public_keys: list[HexStr], +) -> HexStr: + encoded_consolidations = _encode_consolidations(source_public_keys, target_public_keys) + return _create_and_sign_message( + vault=vault, + validators=encoded_consolidations, + validators_registry_root=validators_manager_nonce.to_bytes(32, byteorder='big'), + ) + +def _encode_validator(v: Validator) -> bytes: + encoded_validator = [ + Web3.to_bytes(hexstr=v.public_key), + Web3.to_bytes(hexstr=v.deposit_signature), + Web3.to_bytes(hexstr=v.deposit_data_root), + ] + if v.validator_type == ValidatorType.V2: + encoded_validator.append(v.amount.to_bytes(8, byteorder='big')) + return b''.join(encoded_validator) + + +def _encode_withdrawals(public_keys: list[HexStr], amounts: list[Gwei]) -> bytes: + data = b'' + for public_key, amount in zip(public_keys, amounts): + data += Web3.to_bytes(hexstr=public_key) + data += amount.to_bytes(8, byteorder='big') + + return data + + +def _encode_consolidations( + source_public_keys: list[HexStr], target_public_keys: list[HexStr] +) -> bytes: + validators_data = b'' + for source_key, target_key in zip(source_public_keys, target_public_keys): + validators_data += Web3.to_bytes(hexstr=source_key) + validators_data += Web3.to_bytes(hexstr=target_key) + return validators_data + + +def _create_and_sign_message( + vault: ChecksumAddress, validators: bytes, validators_registry_root: bytes +) -> HexStr: full_message = { 'primaryType': 'VaultValidators', 'types': { @@ -81,8 +128,8 @@ def get_validators_manager_signature_with_nonce( 'verifyingContract': vault, }, 'message': { - 'validatorsRegistryRoot': validators_manager_nonce.to_bytes(32, byteorder='big'), - 'validators': b''.join(encoded_validators), + 'validatorsRegistryRoot': validators_registry_root, + 'validators': validators, }, } @@ -91,14 +138,3 @@ def get_validators_manager_signature_with_nonce( signed_msg = app_state.validators_manager_account.sign_message(encoded_message) return HexStr(signed_msg.signature.hex()) - - -def _encode_validator(v: Validator) -> bytes: - encoded_validator = [ - Web3.to_bytes(hexstr=v.public_key), - Web3.to_bytes(hexstr=v.deposit_signature), - Web3.to_bytes(hexstr=v.deposit_data_root), - ] - if v.validator_type == ValidatorType.V2: - encoded_validator.append(v.amount.to_bytes(8, byteorder='big')) - return b''.join(encoded_validator)