Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion evm/script/helpers/DeployWormholeNttBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ contract DeployWormholeNttBase is ParseNttConfig {
}

// Hardcoded to one since these scripts handle Wormhole-only deployments.
INttManager(nttManager).setThreshold(1);
// TODO: We need the sourceChainId to set the threshold. Also need to enable sending and receiving.
// INttManager(nttManager).setThreshold(1);
console2.log("Threshold set on NttManager: %d", uint256(1));
}

Expand Down
107 changes: 23 additions & 84 deletions evm/src/NttManager/ManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ abstract contract ManagerBase is
}

function _migrate() internal virtual override {
_checkThresholdInvariants();
_checkTransceiversInvariants();
}

Expand All @@ -68,13 +67,6 @@ abstract contract ManagerBase is

// =============== Storage Getters/Setters ==============================================

function _getThresholdStorage() private pure returns (_Threshold storage $) {
uint256 slot = uint256(THRESHOLD_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}

function _getMessageAttestationsStorage()
internal
pure
Expand Down Expand Up @@ -139,15 +131,19 @@ abstract contract ManagerBase is
bytes32 nttManagerMessageHash =
TransceiverStructs.nttManagerMessageDigest(sourceChainId, payload);

// The `msg.sender` is the transceiver. Get the index for it.
uint8 index = _getTransceiverInfosStorage()[msg.sender].index;

// TODO: Is there a race condition with disabling a transceiver while a tx is outstanding?
if (!_isRecvTransceiverEnabledForChain(sourceChainId, index)) {
revert CallerNotTransceiver(msg.sender);
}

// set the attested flag for this transceiver.
// NOTE: Attestation is idempotent (bitwise or 1), but we revert
// anyway to ensure that the client does not continue to initiate calls
// to receive the same message through the same transceiver.
if (
transceiverAttestedToMessage(
nttManagerMessageHash, _getTransceiverInfosStorage()[msg.sender].index
)
) {
if (transceiverAttestedToMessage(nttManagerMessageHash, index)) {
revert TransceiverAlreadyAttestedToMessage(nttManagerMessageHash);
}
_setTransceiverAttestedToMessage(nttManagerMessageHash, msg.sender);
Expand All @@ -162,7 +158,7 @@ abstract contract ManagerBase is
) internal returns (bytes32, bool) {
bytes32 digest = TransceiverStructs.nttManagerMessageDigest(sourceChainId, message);

if (!isMessageApproved(digest)) {
if (!isMessageApproved(sourceChainId, digest)) {
revert MessageNotApproved(digest);
}

Expand Down Expand Up @@ -225,7 +221,7 @@ abstract contract ManagerBase is
)
{
// cache enabled transceivers to avoid multiple storage reads
address[] memory enabledTransceivers = _getEnabledTransceiversStorage();
address[] memory enabledTransceivers = getEnabledSendTransceiversForChain(recipientChain);

TransceiverStructs.TransceiverInstruction[] memory instructions;

Expand Down Expand Up @@ -280,15 +276,16 @@ abstract contract ManagerBase is
}

/// @inheritdoc IManagerBase
function getThreshold() public view returns (uint8) {
return _getThresholdStorage().num;
/// @dev This is here because it is defined in IManagerBase.
function getThreshold(
uint16 sourceChainId
) public view returns (uint8) {
return _getPerChainRecvTransceiverDataStorage()[sourceChainId].threshold;
}

/// @inheritdoc IManagerBase
function isMessageApproved(
bytes32 digest
) public view returns (bool) {
uint8 threshold = getThreshold();
function isMessageApproved(uint16 sourceChainId, bytes32 digest) public view returns (bool) {
uint8 threshold = getThreshold(sourceChainId);
return messageAttestations(digest) >= threshold && threshold > 0;
}

Expand Down Expand Up @@ -354,63 +351,21 @@ abstract contract ManagerBase is
address transceiver
) external onlyOwner {
_setTransceiver(transceiver);

_Threshold storage _threshold = _getThresholdStorage();
// We do not automatically increase the threshold here.
// Automatically increasing the threshold can result in a scenario
// where in-flight messages can't be redeemed.
// For example: Assume there is 1 Transceiver and the threshold is 1.
// If we were to add a new Transceiver, the threshold would increase to 2.
// However, all messages that are either in-flight or that are sent on
// a source chain that does not yet have 2 Transceivers will only have been
// sent from a single transceiver, so they would never be able to get
// redeemed.
// Instead, we leave it up to the owner to manually update the threshold
// after some period of time, ideally once all chains have the new Transceiver
// and transfers that were sent via the old configuration are all complete.
// However if the threshold is 0 (the initial case) we do increment to 1.
if (_threshold.num == 0) {
_threshold.num = 1;
}

emit TransceiverAdded(transceiver, _getNumTransceiversStorage().enabled, _threshold.num);

_checkThresholdInvariants();
emit TransceiverAdded(transceiver, _getNumTransceiversStorage().enabled);
}

/// @inheritdoc IManagerBase
function removeTransceiver(
address transceiver
) external onlyOwner {
_removeTransceiver(transceiver);

_Threshold storage _threshold = _getThresholdStorage();
uint8 numEnabledTransceivers = _getNumTransceiversStorage().enabled;

if (numEnabledTransceivers < _threshold.num) {
_threshold.num = numEnabledTransceivers;
}

emit TransceiverRemoved(transceiver, _threshold.num);

_checkThresholdInvariants();
emit TransceiverRemoved(transceiver);
}

/// @inheritdoc IManagerBase
function setThreshold(
uint8 threshold
) external onlyOwner {
if (threshold == 0) {
revert ZeroThreshold();
}

_Threshold storage _threshold = _getThresholdStorage();
uint8 oldThreshold = _threshold.num;

_threshold.num = threshold;
_checkThresholdInvariants();

emit ThresholdChanged(oldThreshold, threshold);
/// @dev This is here because it is defined in IManagerBase.
function setThreshold(uint16 sourceChainId, uint8 threshold) external onlyOwner {
_setThreshold(sourceChainId, threshold);
}

// =============== Internal ==============================================================
Expand Down Expand Up @@ -480,20 +435,4 @@ abstract contract ManagerBase is
);
}
}

function _checkThresholdInvariants() internal view {
uint8 threshold = _getThresholdStorage().num;
_NumTransceivers memory numTransceivers = _getNumTransceiversStorage();

// invariant: threshold <= enabledTransceivers.length
if (threshold > numTransceivers.enabled) {
revert ThresholdTooHigh(threshold, numTransceivers.enabled);
}

if (numTransceivers.registered > 0) {
if (threshold == 0) {
revert ZeroThreshold();
}
}
}
}
3 changes: 1 addition & 2 deletions evm/src/NttManager/NttManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ contract NttManager is INttManager, RateLimiter, ManagerBase {

function _initialize() internal virtual override {
__NttManager_init();
_checkThresholdInvariants();
_checkTransceiversInvariants();
}

Expand Down Expand Up @@ -192,7 +191,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase {
// Compute manager message digest and record transceiver attestation.
bytes32 nttManagerMessageHash = _recordTransceiverAttestation(sourceChainId, payload);

if (isMessageApproved(nttManagerMessageHash)) {
if (isMessageApproved(sourceChainId, nttManagerMessageHash)) {
executeMsg(sourceChainId, sourceNttManagerAddress, payload);
}
}
Expand Down
Loading
Loading