Skip to content

Commit

Permalink
Merge branch 'main' into rename-icm
Browse files Browse the repository at this point in the history
  • Loading branch information
geoff-vball committed Nov 27, 2024
2 parents 13e34cf + 790ccce commit 09e2316
Show file tree
Hide file tree
Showing 64 changed files with 5,872 additions and 2,018 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ This directory is set up as a [Foundry](https://github.com/foundry-rs/foundry) p

## Generate documentation
- Documentation can be generated by running `forge doc --build` from this repository. By default, this will generate documentation to `contracts/docs/`, and an HTML book to `contracts/docs/book/`. It's also possible to serve this book locally by running `forge doc --serve <PORT>`.

## Audits

In general, the contracts in this repository have been audited. Any unaudited contracts will be explicitly marked as such. Note that the `main` branch may contain unaudited code. Please check [here](../audits/README.md) for which versions of each contract have been audited.

> [!CAUTION]
> DO NOT USE UN-AUDITED CODE IN PRODUCTION!
7 changes: 0 additions & 7 deletions contracts/ictt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ The token transferrer also supports "multi-hop" transfers, where tokens can be t

In addition to supporting basic token transfers, the token transferrer contracts offer a `sendAndCall` interface for transferring tokens and using them in a smart contract interaction all within a single ICM message. If the call to the recipient smart contract fails, the transferred tokens are sent to a fallback recipient address on the destination chain of the transfer. The `sendAndCall` interface enables the direct use of transferred tokens in dApps on other chains, such as performing swaps, using the tokens to pay for fees when invoking services, etc.

A breakdown of the structure of the contracts that implement this function can be found under `./contracts` [here](./contracts/README.md).

## Audits

Some contracts in this repository have been audited. The `main` branch may contain unaudited code. Please check [here](./audits/README.md) for which versions of each contract have been audited.
DO NOT USE UN-AUDITED CODE IN PRODUCTION!

## Upgradability

The token transferrer contracts implement both upgradeable and non-upgradeable versions. The non-upgradeable versions are extensions of their respective upgradeable token transferrer contract, and has a `constructor` that calls the `initialize` function of the upgradeable version. The upgradeable contracts are ERC7201 compliant, and use namespace storage to store the state of the contract.
Expand Down
7 changes: 7 additions & 0 deletions contracts/validator-manager/ERC20TokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ contract ERC20TokenStakingManager is
return _initializeDelegatorRegistration(validationID, _msgSender(), delegationAmount);
}

/**
* @notice Returns the ERC20 token being staked
*/
function erc20() external view returns (IERC20Mintable) {
return _getERC20StakingManagerStorage()._token;
}

/**
* @notice See {PoSValidatorManager-_lock}
* Note: Must be guarded with reentrancy guard for safe transfer from.
Expand Down
45 changes: 22 additions & 23 deletions contracts/validator-manager/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,7 @@ abstract contract PoSValidatorManager is
revert UnauthorizedOwner(_msgSender());
}

if (rewardRecipient == _msgSender()) {
delete $._rewardRecipients[validationID];
} else {
$._rewardRecipients[validationID] = rewardRecipient;
}
$._rewardRecipients[validationID] = rewardRecipient;
}

function changeDelegatorRewardRecipient(
Expand All @@ -310,11 +306,7 @@ abstract contract PoSValidatorManager is
revert UnauthorizedOwner(_msgSender());
}

if (rewardRecipient == _msgSender()) {
delete $._delegatorRewardRecipients[delegationID];
} else {
$._delegatorRewardRecipients[delegationID] = rewardRecipient;
}
$._delegatorRewardRecipients[delegationID] = rewardRecipient;
}

/**
Expand Down Expand Up @@ -365,12 +357,14 @@ abstract contract PoSValidatorManager is
stakingEndTime: validator.endedAt,
uptimeSeconds: uptimeSeconds
});
$._redeemableValidatorRewards[validationID] += reward;

if (rewardRecipient != address(0)) {
$._rewardRecipients[validationID] = rewardRecipient;
if (rewardRecipient == address(0)) {
rewardRecipient = $._posValidatorInfo[validationID].owner;
}

$._redeemableValidatorRewards[validationID] += reward;
$._rewardRecipients[validationID] = rewardRecipient;

return (reward > 0);
}

Expand All @@ -389,13 +383,12 @@ abstract contract PoSValidatorManager is
}

address owner = $._posValidatorInfo[validationID].owner;

address rewardRecipient = $._rewardRecipients[validationID];
delete $._rewardRecipients[validationID];

// the reward-recipient should always be set, but just in case it isn't, we won't burn the reward
if (rewardRecipient == address(0)) {
rewardRecipient = owner;
} else {
delete $._rewardRecipients[validationID];
}

// The validator can either be Completed or Invalidated here. We only grant rewards for Completed.
Expand Down Expand Up @@ -479,10 +472,14 @@ abstract contract PoSValidatorManager is
uint64 weight = valueToWeight(lockedValue);
bytes32 validationID = _initializeValidatorRegistration(registrationInput, weight);

$._posValidatorInfo[validationID].owner = _msgSender();
address owner = _msgSender();

$._posValidatorInfo[validationID].owner = owner;
$._posValidatorInfo[validationID].delegationFeeBips = delegationFeeBips;
$._posValidatorInfo[validationID].minStakeDuration = minStakeDuration;
$._posValidatorInfo[validationID].uptimeSeconds = 0;
$._rewardRecipients[validationID] = owner;

return validationID;
}

Expand Down Expand Up @@ -782,6 +779,7 @@ abstract contract PoSValidatorManager is
} else if (validator.status == ValidatorStatus.Active) {
delegationEndTime = uint64(block.timestamp);
} else {
// Should be unreachable.
revert InvalidValidatorStatus(validator.status);
}

Expand All @@ -798,12 +796,13 @@ abstract contract PoSValidatorManager is
uptimeSeconds: $._posValidatorInfo[delegator.validationID].uptimeSeconds
});

$._redeemableDelegatorRewards[delegationID] = reward;

if (rewardRecipient != address(0)) {
$._delegatorRewardRecipients[delegationID] = rewardRecipient;
if (rewardRecipient == address(0)) {
rewardRecipient = delegator.owner;
}

$._redeemableDelegatorRewards[delegationID] = reward;
$._delegatorRewardRecipients[delegationID] = rewardRecipient;

return reward;
}

Expand All @@ -824,6 +823,7 @@ abstract contract PoSValidatorManager is

Validator memory validator = getValidator(delegator.validationID);
if (validator.messageNonce == 0) {
// Should be unreachable.
revert InvalidDelegationID(delegationID);
}

Expand Down Expand Up @@ -890,11 +890,10 @@ abstract contract PoSValidatorManager is
delete $._delegatorStakes[delegationID];

address rewardRecipient = $._delegatorRewardRecipients[delegationID];
delete $._delegatorRewardRecipients[delegationID];

if (rewardRecipient == address(0)) {
rewardRecipient = delegator.owner;
} else {
delete $._delegatorRewardRecipients[delegationID];
}

(uint256 delegationRewards, uint256 validatorFees) =
Expand Down
3 changes: 0 additions & 3 deletions contracts/validator-manager/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Validator Manager Contract

> [!CAUTION]
> The contracts in this directory are still under active development, are unaudited, and should not be used in production.
The contracts in this directory define the Validator Manager used to manage Avalanche L1 validators, as defined in [ACP-77](https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/77-reinventing-subnets). `ValidatorManager.sol` is the top-level abstract contract that provides the basic functionality. The other contracts are related as follows:

```mermaid
Expand Down
11 changes: 8 additions & 3 deletions contracts/validator-manager/ValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida
error InvalidBLSKeyLength(uint256 length);
error InvalidNodeID(bytes nodeID);
error InvalidConversionID(bytes32 encodedConversionID, bytes32 expectedConversionID);
error InvalidTotalWeight(uint256 weight);
error InvalidTotalWeight(uint64 weight);
error InvalidValidationID(bytes32 validationID);
error InvalidValidatorStatus(ValidatorStatus status);
error InvalidWarpMessage();
Expand Down Expand Up @@ -160,7 +160,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida

uint256 numInitialValidators = conversionData.initialValidators.length;

uint256 totalWeight;
uint64 totalWeight;
for (uint32 i; i < numInitialValidators; ++i) {
InitialValidator memory initialValidator = conversionData.initialValidators[i];
if ($._registeredValidators[initialValidator.nodeID] != bytes32(0)) {
Expand Down Expand Up @@ -246,6 +246,11 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida
revert InvalidRegistrationExpiry(input.registrationExpiry);
}

// Ensure the new validator doesn't overflow the total weight
if (uint256(weight) + uint256($._churnTracker.totalWeight) > type(uint64).max) {
revert InvalidTotalWeight(weight);
}

_validatePChainOwner(input.remainingBalanceOwner);
_validatePChainOwner(input.disableOwner);

Expand Down Expand Up @@ -520,7 +525,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida
emit ValidatorWeightUpdate({
validationID: validationID,
nonce: nonce,
validatorWeight: newWeight,
weight: newWeight,
setWeightMessageID: messageID
});

Expand Down
2 changes: 1 addition & 1 deletion contracts/validator-manager/ValidatorMessages.sol
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ library ValidatorMessages {
* @param conversionData The struct representing data to pack into the message.
* @return The packed message.
*/
function packConversionData(ConversionData calldata conversionData)
function packConversionData(ConversionData memory conversionData)
external
pure
returns (bytes memory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ interface IPoSValidatorManager is IValidatorManager {

/**
* @notice See {IPoSValidatorManager-initializeEndValidation} for details of the first three parameters
* @param recipientAddress The address to receive the rewards
* @param recipientAddress The address to receive the rewards. If the 0-address is provided, the rewards will be sent to the validator.
*/
function initializeEndValidation(
bytes32 validationID,
Expand Down Expand Up @@ -226,7 +226,7 @@ interface IPoSValidatorManager is IValidatorManager {

/**
* @notice See {IPoSValidatorManager-initializeEndDelegation} for details of the first three parameters
* @param recipientAddress The address to receive the rewards.
* @param recipientAddress The address to receive the rewards. If the 0-address is provided, the rewards will be sent to the delegator.
*/
function initializeEndDelegation(
bytes32 delegationID,
Expand Down
16 changes: 8 additions & 8 deletions contracts/validator-manager/interfaces/IValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ struct Validator {
*/
struct ValidatorChurnPeriod {
uint256 startedAt;
uint256 initialWeight;
uint256 totalWeight;
uint64 initialWeight;
uint64 totalWeight;
uint64 churnAmount;
}

Expand Down Expand Up @@ -114,12 +114,12 @@ interface IValidatorManager {
bytes32 indexed validationID,
bytes indexed nodeID,
bytes32 indexed registerValidationMessageID,
uint256 weight,
uint64 weight,
uint64 registrationExpiry
);

event InitialValidatorCreated(
bytes32 indexed validationID, bytes indexed nodeID, uint256 weight
bytes32 indexed validationID, bytes indexed nodeID, uint64 weight
);

/**
Expand All @@ -130,7 +130,7 @@ interface IValidatorManager {
* @param timestamp The time at which the validation period was registered with the contract.
*/
event ValidationPeriodRegistered(
bytes32 indexed validationID, uint256 weight, uint256 timestamp
bytes32 indexed validationID, uint64 weight, uint256 timestamp
);

/**
Expand All @@ -145,7 +145,7 @@ interface IValidatorManager {
event ValidatorRemovalInitialized(
bytes32 indexed validationID,
bytes32 indexed setWeightMessageID,
uint256 weight,
uint64 weight,
uint256 endTime
);

Expand All @@ -161,13 +161,13 @@ interface IValidatorManager {
* @notice Event emitted when validator weight is updated.
* @param validationID The ID of the validation period being updated
* @param nonce The message nonce used to update the validator weight
* @param validatorWeight The updated validator weight that is sent to the P-Chain
* @param weight The updated validator weight that is sent to the P-Chain
* @param setWeightMessageID The ID of the ICM message that updates the validator's weight on the P-Chain
*/
event ValidatorWeightUpdate(
bytes32 indexed validationID,
uint64 indexed nonce,
uint64 validatorWeight,
uint64 weight,
bytes32 setWeightMessageID
);

Expand Down
Loading

0 comments on commit 09e2316

Please sign in to comment.