diff --git a/src/core/ExoCapsule.sol b/src/core/ExoCapsule.sol index 5e364d1f..a809a00a 100644 --- a/src/core/ExoCapsule.sol +++ b/src/core/ExoCapsule.sol @@ -35,21 +35,21 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul event WithdrawalSuccess(address owner, address recipient, uint256 amount); /// @notice Emitted when a partial withdrawal claim is successfully redeemed - /// @param pubkey The validator's BLS12-381 public key. + /// @param pubkeyHash The validator's BLS12-381 public key hash. /// @param withdrawalEpoch The epoch at which the withdrawal was made. /// @param recipient The address of the recipient of the withdrawal. /// @param partialWithdrawalAmountGwei The amount of the partial withdrawal in Gwei. event PartialWithdrawalRedeemed( - bytes32 pubkey, uint256 withdrawalEpoch, address indexed recipient, uint64 partialWithdrawalAmountGwei + bytes32 pubkeyHash, uint256 withdrawalEpoch, address indexed recipient, uint64 partialWithdrawalAmountGwei ); /// @notice Emitted when an ETH validator is prove to have fully withdrawn from the beacon chain - /// @param pubkey The validator's BLS12-381 public key. + /// @param pubkeyHash The validator's BLS12-381 public key hash. /// @param withdrawalEpoch The epoch at which the withdrawal was made. /// @param recipient The address of the recipient of the withdrawal. /// @param withdrawalAmountGwei The amount of the withdrawal in Gwei. event FullWithdrawalRedeemed( - bytes32 pubkey, uint64 withdrawalEpoch, address indexed recipient, uint64 withdrawalAmountGwei + bytes32 pubkeyHash, uint64 withdrawalEpoch, address indexed recipient, uint64 withdrawalAmountGwei ); /// @notice Emitted when capsuleOwner enables restaking @@ -66,34 +66,34 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul event NonBeaconChainETHWithdrawn(address indexed recipient, uint256 amountWithdrawn); /// @dev Thrown when the validator container is invalid. - /// @param pubkey The validator's BLS12-381 public key. - error InvalidValidatorContainer(bytes32 pubkey); + /// @param pubkeyHash The validator's BLS12-381 public key hash. + error InvalidValidatorContainer(bytes32 pubkeyHash); /// @dev Thrown when the withdrawal container is invalid. /// @param validatorIndex The validator index. error InvalidWithdrawalContainer(uint64 validatorIndex); /// @dev Thrown when a validator is double deposited. - /// @param pubkey The validator's BLS12-381 public key. - error DoubleDepositedValidator(bytes32 pubkey); + /// @param pubkeyHash The validator's BLS12-381 public key hash. + error DoubleDepositedValidator(bytes32 pubkeyHash); /// @dev Thrown when a validator container is stale. - /// @param pubkey The validator's BLS12-381 public key. + /// @param pubkeyHash The validator's BLS12-381 public key hash. /// @param timestamp The timestamp of the validator proof. - error StaleValidatorContainer(bytes32 pubkey, uint256 timestamp); + error StaleValidatorContainer(bytes32 pubkeyHash, uint256 timestamp); /// @dev Thrown when a withdrawal has already been proven. - /// @param pubkey The validator's BLS12-381 public key. + /// @param pubkeyHash The validator's BLS12-381 public key hash. /// @param withdrawalIndex The index of the withdrawal. - error WithdrawalAlreadyProven(bytes32 pubkey, uint256 withdrawalIndex); + error WithdrawalAlreadyProven(bytes32 pubkeyHash, uint256 withdrawalIndex); /// @dev Thrown when a validator container is unregistered. - /// @param pubkey The validator's BLS12-381 public key. - error UnregisteredValidator(bytes32 pubkey); + /// @param pubkeyHash The validator's BLS12-381 public key hash. + error UnregisteredValidator(bytes32 pubkeyHash); /// @dev Thrown when a validator container is unregistered or withdrawn. - /// @param pubkey The validator's BLS12-381 public key. - error UnregisteredOrWithdrawnValidatorContainer(bytes32 pubkey); + /// @param pubkeyHash The validator's BLS12-381 public key hash. + error UnregisteredOrWithdrawnValidatorContainer(bytes32 pubkeyHash); /// @dev Thrown when the validator and withdrawal state roots do not match. /// @param validatorStateRoot The state root of the validator container. @@ -115,8 +115,8 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul error WithdrawalCredentialsNotMatch(); /// @dev Thrown when the validator container is inactive. - /// @param pubkey The validator's BLS12-381 public key. - error InactiveValidatorContainer(bytes32 pubkey); + /// @param pubkeyHash The validator's BLS12-381 public key hash. + error InactiveValidatorContainer(bytes32 pubkeyHash); /// @dev Thrown when the caller of a message is not the gateway /// @param gateway The address of the gateway. @@ -162,20 +162,20 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul bytes32[] calldata validatorContainer, BeaconChainProofs.ValidatorContainerProof calldata proof ) external onlyGateway returns (uint256 depositAmount) { - bytes32 validatorPubkey = validatorContainer.getPubkey(); + bytes32 validatorPubkeyHash = validatorContainer.getPubkeyHash(); bytes32 withdrawalCredentials = validatorContainer.getWithdrawalCredentials(); - Validator storage validator = _capsuleValidators[validatorPubkey]; + Validator storage validator = _capsuleValidators[validatorPubkeyHash]; if (!validatorContainer.verifyValidatorContainerBasic()) { - revert InvalidValidatorContainer(validatorPubkey); + revert InvalidValidatorContainer(validatorPubkeyHash); } if (validator.status != VALIDATOR_STATUS.UNREGISTERED) { - revert DoubleDepositedValidator(validatorPubkey); + revert DoubleDepositedValidator(validatorPubkeyHash); } if (_isStaleProof(proof.beaconBlockTimestamp)) { - revert StaleValidatorContainer(validatorPubkey, proof.beaconBlockTimestamp); + revert StaleValidatorContainer(validatorPubkeyHash, proof.beaconBlockTimestamp); } if (withdrawalCredentials != bytes32(capsuleWithdrawalCredentials())) { @@ -193,7 +193,7 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul depositAmount = depositAmountGwei * GWEI_TO_WEI; } - _capsuleValidatorsByIndex[proof.validatorIndex] = validatorPubkey; + _capsuleValidatorsByIndex[proof.validatorIndex] = validatorPubkeyHash; } /// @inheritdoc IExoCapsule @@ -203,24 +203,24 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul bytes32[] calldata withdrawalContainer, BeaconChainProofs.WithdrawalProof calldata withdrawalProof ) external onlyGateway returns (bool partialWithdrawal, uint256 withdrawalAmount) { - bytes32 validatorPubkey = validatorContainer.getPubkey(); - Validator storage validator = _capsuleValidators[validatorPubkey]; + bytes32 validatorPubkeyHash = validatorContainer.getPubkeyHash(); + Validator storage validator = _capsuleValidators[validatorPubkeyHash]; uint64 withdrawalEpoch = withdrawalProof.slotRoot.getWithdrawalEpoch(); partialWithdrawal = withdrawalEpoch < validatorContainer.getWithdrawableEpoch(); uint256 withdrawalId = uint256(withdrawalContainer.getWithdrawalIndex()); if (!validatorContainer.verifyValidatorContainerBasic()) { - revert InvalidValidatorContainer(validatorPubkey); + revert InvalidValidatorContainer(validatorPubkeyHash); } if (validator.status == VALIDATOR_STATUS.UNREGISTERED) { - revert UnregisteredOrWithdrawnValidatorContainer(validatorPubkey); + revert UnregisteredOrWithdrawnValidatorContainer(validatorPubkeyHash); } - if (provenWithdrawal[validatorPubkey][withdrawalId]) { - revert WithdrawalAlreadyProven(validatorPubkey, withdrawalId); + if (provenWithdrawal[validatorPubkeyHash][withdrawalId]) { + revert WithdrawalAlreadyProven(validatorPubkeyHash, withdrawalId); } - provenWithdrawal[validatorPubkey][withdrawalId] = true; + provenWithdrawal[validatorPubkeyHash][withdrawalId] = true; // Validate if validator and withdrawal proof state roots are the same if (validatorProof.stateRoot != withdrawalProof.stateRoot) { @@ -234,13 +234,13 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul if (partialWithdrawal) { // Immediately send ETH without sending request to Exocore side - emit PartialWithdrawalRedeemed(validatorPubkey, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); + emit PartialWithdrawalRedeemed(validatorPubkeyHash, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); _sendETH(capsuleOwner, withdrawalAmountGwei * GWEI_TO_WEI); } else { // Full withdrawal validator.status = VALIDATOR_STATUS.WITHDRAWN; // If over MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32 * 1e9, then send remaining amount immediately - emit FullWithdrawalRedeemed(validatorPubkey, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); + emit FullWithdrawalRedeemed(validatorPubkeyHash, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); if (withdrawalAmountGwei > MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) { uint256 amountToSend = (withdrawalAmountGwei - MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) * GWEI_TO_WEI; _sendETH(capsuleOwner, amountToSend); @@ -312,14 +312,14 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul return root; } - /// @notice Gets the registered validator by pubkey. + /// @notice Gets the registered validator by pubkeyHash. /// @dev The validator status must be registered. Reverts if not. - /// @param pubkey The validator's BLS12-381 public key. + /// @param pubkeyHash The validator's BLS12-381 public key hash. /// @return The validator object, as defined in the `ExoCapsuleStorage`. - function getRegisteredValidatorByPubkey(bytes32 pubkey) public view returns (Validator memory) { - Validator memory validator = _capsuleValidators[pubkey]; + function getRegisteredValidatorByPubkey(bytes32 pubkeyHash) public view returns (Validator memory) { + Validator memory validator = _capsuleValidators[pubkeyHash]; if (validator.status == VALIDATOR_STATUS.UNREGISTERED) { - revert UnregisteredValidator(pubkey); + revert UnregisteredValidator(pubkeyHash); } return validator; @@ -366,7 +366,7 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul proof.stateRootProof ); if (!valid) { - revert InvalidValidatorContainer(validatorContainer.getPubkey()); + revert InvalidValidatorContainer(validatorContainer.getPubkeyHash()); } } diff --git a/src/core/ExocoreGateway.sol b/src/core/ExocoreGateway.sol index 99058203..d839ffe7 100644 --- a/src/core/ExocoreGateway.sol +++ b/src/core/ExocoreGateway.sol @@ -374,21 +374,25 @@ contract ExocoreGateway is onlyCalledFromThis returns (bytes memory response) { - bytes calldata validatorPubkey = payload[:32]; - bytes calldata staker = payload[32:64]; - uint256 amount = uint256(bytes32(payload[64:96])); + bytes calldata staker = payload[:32]; + uint256 amount = uint256(bytes32(payload[32:64])); + // the length of the validatorID is not known. it depends on the chain. + // for Ethereum, it is the validatorIndex uint256 as bytes so it becomes 32. its value may be 0. + // for Solana, the pubkey is 32 bytes long but for Sui it is 96 bytes long. + // these chains do not have the concept of validatorIndex, so the raw key must be used. + bytes calldata validatorID = payload[64:]; bool isDeposit = act == Action.REQUEST_DEPOSIT_NST; bool success; if (isDeposit) { - (success,) = ASSETS_CONTRACT.depositNST(srcChainId, validatorPubkey, staker, amount); + (success,) = ASSETS_CONTRACT.depositNST(srcChainId, validatorID, staker, amount); } else { - (success,) = ASSETS_CONTRACT.withdrawNST(srcChainId, validatorPubkey, staker, amount); + (success,) = ASSETS_CONTRACT.withdrawNST(srcChainId, validatorID, staker, amount); } if (isDeposit && !success) { revert Errors.DepositRequestShouldNotFail(srcChainId, lzNonce); // we should not let this happen } - emit NSTTransfer(isDeposit, success, bytes32(validatorPubkey), bytes32(staker), amount); + emit NSTTransfer(isDeposit, success, validatorID, bytes32(staker), amount); response = isDeposit ? bytes("") : abi.encodePacked(lzNonce, success); } diff --git a/src/core/NativeRestakingController.sol b/src/core/NativeRestakingController.sol index 16fd28aa..d9f35674 100644 --- a/src/core/NativeRestakingController.sol +++ b/src/core/NativeRestakingController.sol @@ -94,8 +94,7 @@ abstract contract NativeRestakingController is IExoCapsule capsule = _getCapsule(msg.sender); uint256 depositValue = capsule.verifyDepositProof(validatorContainer, proof); - bytes32 validatorPubkey = validatorContainer.getPubkey(); - bytes memory actionArgs = abi.encodePacked(validatorPubkey, bytes32(bytes20(msg.sender)), depositValue); + bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(msg.sender)), depositValue, proof.validatorIndex); // deposit NST is a must-succeed action, so we don't need to check the response _processRequest(Action.REQUEST_DEPOSIT_NST, actionArgs, bytes("")); @@ -117,8 +116,8 @@ abstract contract NativeRestakingController is capsule.verifyWithdrawalProof(validatorContainer, validatorProof, withdrawalContainer, withdrawalProof); if (!partialWithdrawal) { // request full withdraw - bytes32 validatorPubkey = validatorContainer.getPubkey(); - bytes memory actionArgs = abi.encodePacked(validatorPubkey, bytes32(bytes20(msg.sender)), withdrawalAmount); + bytes memory actionArgs = + abi.encodePacked(bytes32(bytes20(msg.sender)), withdrawalAmount, validatorProof.validatorIndex); bytes memory encodedRequest = abi.encode(VIRTUAL_NST_ADDRESS, msg.sender, withdrawalAmount); // a full withdrawal needs response from Exocore, so we don't pass empty bytes diff --git a/src/interfaces/precompiles/IAssets.sol b/src/interfaces/precompiles/IAssets.sol index ff33a78e..f1f11c37 100644 --- a/src/interfaces/precompiles/IAssets.sol +++ b/src/interfaces/precompiles/IAssets.sol @@ -37,12 +37,12 @@ interface IAssets { /// @param clientChainID is the layerZero chainID if it is supported. // It might be allocated by Exocore when the client chain isn't supported // by layerZero - /// @param validatorPubkey The validator's pubkey + /// @param validatorID The validator's identifier: index (uint256 as bytes32) or pubkey. /// @param stakerAddress The staker address /// @param opAmount The amount to deposit function depositNST( uint32 clientChainID, - bytes calldata validatorPubkey, + bytes calldata validatorID, bytes calldata stakerAddress, uint256 opAmount ) external returns (bool success, uint256 latestAssetState); @@ -67,12 +67,12 @@ interface IAssets { /// @param clientChainID is the layerZero chainID if it is supported. // It might be allocated by Exocore when the client chain isn't supported // by layerZero - /// @param validatorPubkey The validator's pubkey + /// @param validatorID The validator's identifier: index (uint256 as bytes32) or pubkey. /// @param withdrawAddress The withdraw address /// @param opAmount The withdraw amount function withdrawNST( uint32 clientChainID, - bytes calldata validatorPubkey, + bytes calldata validatorID, bytes calldata withdrawAddress, uint256 opAmount ) external returns (bool success, uint256 latestAssetState); diff --git a/src/libraries/ActionAttributes.sol b/src/libraries/ActionAttributes.sol index 7fa19f69..ecbf3a4c 100644 --- a/src/libraries/ActionAttributes.sol +++ b/src/libraries/ActionAttributes.sol @@ -20,6 +20,7 @@ library ActionAttributes { uint256 internal constant MESSAGE_LENGTH_MASK = 0xFF; // 8 bits for message length uint256 internal constant MESSAGE_LENGTH_SHIFT = 8; + uint256 internal constant MIN_LENGTH_FLAG = 1 << 16; // Flag at the 16th bit function getAttributes(Action action) internal pure returns (uint256) { uint256 attributes = 0; @@ -29,13 +30,15 @@ library ActionAttributes { attributes = LST | PRINCIPAL; messageLength = ASSET_OPERATION_LENGTH; } else if (action == Action.REQUEST_DEPOSIT_NST) { - attributes = NST | PRINCIPAL; + // we assume that a validatorID is at least 32 bytes, however, it is up for review. + attributes = NST | PRINCIPAL | MIN_LENGTH_FLAG; messageLength = ASSET_OPERATION_LENGTH; } else if (action == Action.REQUEST_WITHDRAW_LST) { attributes = LST | PRINCIPAL | WITHDRAWAL; messageLength = ASSET_OPERATION_LENGTH; } else if (action == Action.REQUEST_WITHDRAW_NST) { - attributes = NST | PRINCIPAL | WITHDRAWAL; + // we assume that a validatorID is at least 32 bytes, however, it is up for review. + attributes = NST | PRINCIPAL | WITHDRAWAL | MIN_LENGTH_FLAG; messageLength = ASSET_OPERATION_LENGTH; } else if (action == Action.REQUEST_CLAIM_REWARD) { attributes = REWARD | WITHDRAWAL; @@ -80,8 +83,11 @@ library ActionAttributes { return (getAttributes(action) & REWARD) != 0; } - function getMessageLength(Action action) internal pure returns (uint256) { - return (getAttributes(action) >> MESSAGE_LENGTH_SHIFT) & MESSAGE_LENGTH_MASK; + function getMessageLength(Action action) internal pure returns (bool, uint256) { + uint256 attributes = getAttributes(action); + uint256 length = (attributes >> MESSAGE_LENGTH_SHIFT) & MESSAGE_LENGTH_MASK; + bool isMinLength = (attributes & MIN_LENGTH_FLAG) != 0; + return (isMinLength, length); } } diff --git a/src/libraries/ValidatorContainer.sol b/src/libraries/ValidatorContainer.sol index 813dcf76..3f9092c4 100644 --- a/src/libraries/ValidatorContainer.sol +++ b/src/libraries/ValidatorContainer.sol @@ -5,7 +5,7 @@ import {Endian} from "../libraries/Endian.sol"; /** * class Validator(Container): - * pubkey: BLSPubkey + * pubkeyHash: The validator's BLS12-381 public key hash. * withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals * effective_balance: Gwei # Balance at stake * slashed: boolean @@ -26,7 +26,7 @@ library ValidatorContainer { return validatorContainer.length == VALID_LENGTH; } - function getPubkey(bytes32[] calldata validatorContainer) internal pure returns (bytes32) { + function getPubkeyHash(bytes32[] calldata validatorContainer) internal pure returns (bytes32) { return validatorContainer[0]; } diff --git a/src/storage/ExoCapsuleStorage.sol b/src/storage/ExoCapsuleStorage.sol index fa4cdaa3..153fa3e8 100644 --- a/src/storage/ExoCapsuleStorage.sol +++ b/src/storage/ExoCapsuleStorage.sol @@ -64,11 +64,11 @@ contract ExoCapsuleStorage { /// @notice The address of the Beacon Chain Oracle contract. IBeaconChainOracle public beaconOracle; - /// @dev Mapping of validator pubkey to their corresponding struct. - mapping(bytes32 pubkey => Validator validator) internal _capsuleValidators; + /// @dev Mapping of validator pubkey hash to their corresponding struct. + mapping(bytes32 pubkeyHash => Validator validator) internal _capsuleValidators; - /// @dev Mapping of validator index to their corresponding pubkey. - mapping(uint256 index => bytes32 pubkey) internal _capsuleValidatorsByIndex; + /// @dev Mapping of validator index to their corresponding pubkey hash. + mapping(uint256 index => bytes32 pubkeyHash) internal _capsuleValidatorsByIndex; /// @notice This is a mapping of validatorPubkeyHash to withdrawal index to whether or not they have proven a /// withdrawal diff --git a/src/storage/ExocoreGatewayStorage.sol b/src/storage/ExocoreGatewayStorage.sol index 614c9c72..ecb62adc 100644 --- a/src/storage/ExocoreGatewayStorage.sol +++ b/src/storage/ExocoreGatewayStorage.sol @@ -82,11 +82,11 @@ contract ExocoreGatewayStorage is GatewayStorage { /// @notice Emitted when a NST transfer happens. /// @param isDeposit Whether the transfer is a deposit or a withdraw. /// @param success Whether the transfer was successful. - /// @param validatorPubkey The validator public key. + /// @param validatorID The validator ID (index or pubkey). /// @param staker The address that makes the transfer. /// @param amount The amount of the token transferred. event NSTTransfer( - bool isDeposit, bool indexed success, bytes32 indexed validatorPubkey, bytes32 indexed staker, uint256 amount + bool isDeposit, bool indexed success, bytes indexed validatorID, bytes32 indexed staker, uint256 amount ); /// @notice Emitted upon receiving a delegation request. @@ -128,13 +128,17 @@ contract ExocoreGatewayStorage is GatewayStorage { revert Errors.InvalidMessageLength(); } Action action = Action(uint8(message[0])); - uint256 expectedLength = action.getMessageLength(); + (bool isMinLength, uint256 expectedLength) = action.getMessageLength(); if (expectedLength == 0) { revert Errors.UnsupportedRequest(action); } - if (message.length != expectedLength) { + if (isMinLength) { + if (message.length < expectedLength) { + revert Errors.InvalidMessageLength(); + } + } else if (message.length != expectedLength) { revert Errors.InvalidMessageLength(); } } diff --git a/test/foundry/DepositWithdrawPrinciple.t.sol b/test/foundry/DepositWithdrawPrinciple.t.sol index bc1447fe..4278005a 100644 --- a/test/foundry/DepositWithdrawPrinciple.t.sol +++ b/test/foundry/DepositWithdrawPrinciple.t.sol @@ -24,7 +24,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { bool isDeposit, bool indexed success, bytes32 indexed token, bytes32 indexed account, uint256 amount ); event NSTTransfer( - bool isDeposit, bool indexed success, bytes32 indexed token, bytes32 indexed account, uint256 amount + bool isDeposit, bool indexed success, bytes indexed validatorID, bytes32 indexed account, uint256 amount ); event Transfer(address indexed from, address indexed to, uint256 amount); event CapsuleCreated(address indexed owner, address indexed capsule); @@ -312,7 +312,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { } bytes memory depositRequestPayload = abi.encodePacked( - Action.REQUEST_DEPOSIT_NST, _getPubkey(validatorContainer), bytes32(bytes20(depositor.addr)), depositAmount + Action.REQUEST_DEPOSIT_NST, bytes32(bytes20(depositor.addr)), depositAmount, validatorProof.validatorIndex ); uint256 depositRequestNativeFee = clientGateway.quote(depositRequestPayload); bytes32 depositRequestId = generateUID(outboundNonces[clientChainId], true); @@ -344,7 +344,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { emit NSTTransfer( true, // isDeposit true, // success - bytes32(_getPubkey(validatorContainer)), + abi.encodePacked(bytes32(validatorProof.validatorIndex)), bytes32(bytes20(depositor.addr)), depositAmount ); @@ -442,9 +442,9 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { } bytes memory withdrawRequestPayload = abi.encodePacked( Action.REQUEST_WITHDRAW_NST, - _getPubkey(validatorContainer), bytes32(bytes20(withdrawer.addr)), - withdrawalAmount + withdrawalAmount, + validatorProof.validatorIndex ); uint256 withdrawRequestNativeFee = clientGateway.quote(withdrawRequestPayload); bytes32 withdrawRequestId = generateUID(outboundNonces[clientChainId], true); @@ -481,7 +481,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { emit NSTTransfer( false, // isDeposit (false for withdrawal) true, // success - bytes32(_getPubkey(validatorContainer)), + abi.encodePacked(bytes32(validatorProof.validatorIndex)), bytes32(bytes20(withdrawer.addr)), withdrawalAmount ); diff --git a/test/mocks/AssetsMock.sol b/test/mocks/AssetsMock.sol index dd0f92cf..6f041606 100644 --- a/test/mocks/AssetsMock.sol +++ b/test/mocks/AssetsMock.sol @@ -36,7 +36,7 @@ contract AssetsMock is IAssets { function depositNST( uint32 clientChainLzId, - bytes calldata validatorPubkey, + bytes calldata validatorID, bytes calldata stakerAddress, uint256 opAmount ) external returns (bool success, uint256 latestAssetState) { @@ -44,7 +44,7 @@ contract AssetsMock is IAssets { bytes memory nstAddress = abi.encodePacked(bytes32(bytes20(VIRTUAL_STAKED_ETH_ADDRESS))); principalBalances[clientChainLzId][nstAddress][stakerAddress] += opAmount; - inValidatorSet[stakerAddress][validatorPubkey] = true; + inValidatorSet[stakerAddress][validatorID] = true; return (true, principalBalances[clientChainLzId][nstAddress][stakerAddress]); } @@ -74,7 +74,7 @@ contract AssetsMock is IAssets { function withdrawNST( uint32 clientChainLzId, - bytes calldata validatorPubkey, + bytes calldata validatorID, bytes calldata withdrawer, uint256 opAmount ) external returns (bool success, uint256 latestAssetState) { @@ -85,7 +85,7 @@ contract AssetsMock is IAssets { return (false, 0); } principalBalances[clientChainLzId][nstAddress][withdrawer] -= opAmount; - inValidatorSet[withdrawer][validatorPubkey] = false; + inValidatorSet[withdrawer][validatorID] = false; return (true, principalBalances[clientChainLzId][nstAddress][withdrawer]); } diff --git a/test/mocks/ExocoreGatewayMock.sol b/test/mocks/ExocoreGatewayMock.sol index 23c91b4f..6e1b15ba 100644 --- a/test/mocks/ExocoreGatewayMock.sol +++ b/test/mocks/ExocoreGatewayMock.sol @@ -388,21 +388,21 @@ contract ExocoreGatewayMock is onlyCalledFromThis returns (bytes memory response) { - bytes calldata validatorPubkey = payload[:32]; - bytes calldata staker = payload[32:64]; - uint256 amount = uint256(bytes32(payload[64:96])); + bytes calldata staker = payload[:32]; + uint256 amount = uint256(bytes32(payload[32:64])); + bytes calldata validatorID = payload[64:]; bool isDeposit = act == Action.REQUEST_DEPOSIT_NST; bool success; if (isDeposit) { - (success,) = ASSETS_CONTRACT.depositNST(srcChainId, validatorPubkey, staker, amount); + (success,) = ASSETS_CONTRACT.depositNST(srcChainId, validatorID, staker, amount); } else { - (success,) = ASSETS_CONTRACT.withdrawNST(srcChainId, validatorPubkey, staker, amount); + (success,) = ASSETS_CONTRACT.withdrawNST(srcChainId, validatorID, staker, amount); } if (isDeposit && !success) { revert Errors.DepositRequestShouldNotFail(srcChainId, lzNonce); // we should not let this happen } - emit NSTTransfer(isDeposit, success, bytes32(validatorPubkey), bytes32(staker), amount); + emit NSTTransfer(isDeposit, success, validatorID, bytes32(staker), amount); response = isDeposit ? bytes("") : abi.encodePacked(lzNonce, success); }