Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to fund state sync relayer when using rootchain originated native token #411

Merged
6 changes: 6 additions & 0 deletions contracts/interfaces/root/IRootERC20Predicate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,10 @@ interface IRootERC20Predicate is IL2StateReceiver {
* @return address Address of the child token
*/
function mapToken(IERC20Metadata rootToken) external returns (address);

/**
* @notice Function that retrieves rootchain token that represents Supernets native token
* @return address Address of rootchain token (mapped to Supernets native token)
*/
function nativeTokenRoot() external returns (address);
}
6 changes: 6 additions & 0 deletions contracts/interfaces/root/staking/ICustomSupernetManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ICustomSupernetManager {
event RemovedFromWhitelist(address indexed validator);
event ValidatorRegistered(address indexed validator, uint256[4] blsKey);
event ValidatorDeactivated(address indexed validator);
event GenesisBalanceAdded(address indexed account, uint256 indexed amount);
event GenesisFinalized(uint256 amountValidators);
event StakingEnabled();

Expand Down Expand Up @@ -51,4 +52,9 @@ interface ICustomSupernetManager {

/// @notice returns validator instance based on provided address
function getValidator(address validator_) external view returns (Validator memory);

/// @notice addGenesisBalance is used to specify genesis balance information for genesis accounts on the Supernets.
/// It is applicable only in case Supernets native contract is mapped to a pre-existing rootchain ERC20 token.
/// @param amount represents the amount to be premined in the genesis.
function addGenesisBalance(uint256 amount) external;
}
5 changes: 3 additions & 2 deletions contracts/lib/GenesisLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum GenesisStatus {
}

struct GenesisValidator {
address validator;
address addr;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZeroEkkusu Is this change safe to be made? The expectation for this PR is that the chain needs to be started from the genesis in order to be able to use the premine functionality however, I'm wondering what would happen for the already running chains when they apply this change and is it ok to rename it or revert it just in case to be backward compatible. WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only in the sense that if someone's using the struct in their code, they'd need to update all .validator occurrences to .addr, but it doesn't change anything on the bytecode level.

The actual issue is that appending the uint256 balance shifts the storage layout. Maybe we could create a mapping somewhere instead and record it there.

See my following comment as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about such change? I've introduced an array which stores premine balances and exposed a function that retrieves it (because we are going to need it on the client-side, it is easier that way than having mapping and fetching balances by address key, one by one):
9f63d58

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re your comment/post at the end:

Do you mean that a restart will be required anyway? If so, different storage layouts don't matter because those would be fresh deployments with clean state.

If not:

This also shifts the storage layout of CustomSupernetManager (because there's GenesisSet private _genesis in it).

We can have the array defined and updated in the CustomSupernetManager directly (after all other storage variables and 1 subtracted from the gap), if that works for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that a restart will be required anyway?

It will be required in case one uses rootchain originated token as a native token. Otherwise we don't expect chain reset (redeployment is not expected in that case).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case we'll need to align the storage layouts. Does the solution I proposed work for you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can have the array defined and updated in the CustomSupernetManager directly (after all other storage variables and 1 subtracted from the gap), if that works for you.

Yes, that should work. I'll change it that way most likely. 👍

uint256 initialStake;
}

Expand Down Expand Up @@ -41,7 +41,8 @@ library GenesisLib {
self.genesisValidators.push(GenesisValidator(validator, stake));
} else {
// update values
GenesisValidator storage genesisValidator = self.genesisValidators[_indexOf(self, validator)];
uint256 idx = _indexOf(self, validator);
GenesisValidator storage genesisValidator = self.genesisValidators[idx];
genesisValidator.initialStake += stake;
}
}
Expand Down
12 changes: 7 additions & 5 deletions contracts/root/RootERC20Predicate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ contract RootERC20Predicate is Initializable, IRootERC20Predicate {
bytes32 public constant WITHDRAW_SIG = keccak256("WITHDRAW");
bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
mapping(address => address) public rootTokenToChildToken;
address public nativeTokenRoot;

/**
* @notice Initialization function for RootERC20Predicate
Expand All @@ -32,7 +33,7 @@ contract RootERC20Predicate is Initializable, IRootERC20Predicate {
address newExitHelper,
address newChildERC20Predicate,
address newChildTokenTemplate,
address nativeTokenRootAddress
address newNativeTokenRoot
) external initializer {
require(
newStateSender != address(0) &&
Expand All @@ -45,9 +46,10 @@ contract RootERC20Predicate is Initializable, IRootERC20Predicate {
exitHelper = newExitHelper;
childERC20Predicate = newChildERC20Predicate;
childTokenTemplate = newChildTokenTemplate;
if (nativeTokenRootAddress != address(0)) {
rootTokenToChildToken[nativeTokenRootAddress] = 0x0000000000000000000000000000000000001010;
emit TokenMapped(nativeTokenRootAddress, 0x0000000000000000000000000000000000001010);
if (newNativeTokenRoot != address(0)) {
nativeTokenRoot = newNativeTokenRoot;
rootTokenToChildToken[nativeTokenRoot] = 0x0000000000000000000000000000000000001010;
emit TokenMapped(nativeTokenRoot, 0x0000000000000000000000000000000000001010);
}
}

Expand Down Expand Up @@ -138,5 +140,5 @@ contract RootERC20Predicate is Initializable, IRootERC20Predicate {
}

// slither-disable-next-line unused-state,naming-convention
uint256[50] private __gap;
uint256[49] private __gap;
}
35 changes: 34 additions & 1 deletion contracts/root/staking/CustomSupernetManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../../interfaces/common/IBLS.sol";
import "../../interfaces/IStateSender.sol";
import "../../interfaces/root/staking/ICustomSupernetManager.sol";
import "../../interfaces/root/IExitHelper.sol";
import "../../interfaces/root/IRootERC20Predicate.sol";

contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeable, SupernetManager {
using SafeERC20 for IERC20;
Expand All @@ -27,6 +28,8 @@ contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeabl

GenesisSet private _genesis;
mapping(address => Validator) public validators;
IRootERC20Predicate private _rootERC20Predicate;
mapping(address => uint256) public genesisBalances;

modifier onlyValidator(address validator) {
if (!validators[validator].isActive) revert Unauthorized("VALIDATOR");
Expand All @@ -40,6 +43,7 @@ contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeabl
address newMatic,
address newChildValidatorSet,
address newExitHelper,
address newRootERC20Predicate,
string memory newDomain
) public initializer {
require(
Expand All @@ -52,12 +56,14 @@ contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeabl
bytes(newDomain).length != 0,
"INVALID_INPUT"
);

__SupernetManager_init(newStakeManager);
_bls = IBLS(newBls);
_stateSender = IStateSender(newStateSender);
_matic = IERC20(newMatic);
_childValidatorSet = newChildValidatorSet;
_exitHelper = newExitHelper;
_rootERC20Predicate = IRootERC20Predicate(newRootERC20Predicate);
domain = keccak256(abi.encodePacked(newDomain));
__Ownable2Step_init();
}
Expand Down Expand Up @@ -129,6 +135,33 @@ contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeabl
return validators[validator_];
}

/**
*
* @inheritdoc ICustomSupernetManager
*/
function addGenesisBalance(uint256 amount) external {
require(amount > 0, "CustomSupernetManager: INVALID_AMOUNT");
if (address(_rootERC20Predicate) == address(0)) {
revert Unauthorized("CustomSupernetManager: UNDEFINED_ROOT_ERC20_PREDICATE");
}

IERC20 nativeTokenRoot = IERC20(_rootERC20Predicate.nativeTokenRoot());
if (address(nativeTokenRoot) == address(0)) {
revert Unauthorized("CustomSupernetManager: UNDEFINED_NATIVE_TOKEN_ROOT");
}
require(!_genesis.completed(), "CustomSupernetManager: GENESIS_SET_IS_ALREADY_FINALIZED");

// we need to track EOAs as well in the genesis set, in order to be able to query genesisBalances mapping
_genesis.insert(msg.sender, 0);
genesisBalances[msg.sender] += amount;

// lock native tokens on the root erc20 predicate
nativeTokenRoot.safeTransferFrom(msg.sender, address(_rootERC20Predicate), amount);
ZeroEkkusu marked this conversation as resolved.
Show resolved Hide resolved

// slither-disable-next-line reentrancy-events
emit GenesisBalanceAdded(msg.sender, amount);
}

function _onStake(address validator, uint256 amount) internal override onlyValidator(validator) {
if (_genesis.gatheringGenesisValidators()) {
_genesis.insert(validator, amount);
Expand Down Expand Up @@ -181,5 +214,5 @@ contract CustomSupernetManager is ICustomSupernetManager, Ownable2StepUpgradeabl
}

// slither-disable-next-line unused-state,naming-convention
uint256[50] private __gap;
uint256[48] private __gap;
}
17 changes: 17 additions & 0 deletions docs/interfaces/root/IRootERC20Predicate.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ Function to be used for token mapping
|---|---|---|
| _0 | address | address Address of the child token |

### nativeTokenRoot

```solidity
function nativeTokenRoot() external nonpayable returns (address)
```

Function that retrieves rootchain token that represents Supernets native token




#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | address | address Address of rootchain token (mapped to Supernets native token) |

### onL2StateReceive

```solidity
Expand Down
33 changes: 33 additions & 0 deletions docs/interfaces/root/staking/ICustomSupernetManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ Manages validator access and syncs voting power between the stake manager and va

## Methods

### addGenesisBalance

```solidity
function addGenesisBalance(uint256 amount) external nonpayable
```

addGenesisBalance is used to specify genesis balance information for genesis accounts on the Supernets. It is applicable only in case Supernets native contract is mapped to a pre-existing rootchain ERC20 token.



#### Parameters

| Name | Type | Description |
|---|---|---|
| amount | uint256 | represents the amount to be premined in the genesis. |

### enableStaking

```solidity
Expand Down Expand Up @@ -142,6 +158,23 @@ event AddedToWhitelist(address indexed validator)
|---|---|---|
| validator `indexed` | address | undefined |

### GenesisBalanceAdded

```solidity
event GenesisBalanceAdded(address indexed account, uint256 indexed amount)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| account `indexed` | address | undefined |
| amount `indexed` | uint256 | undefined |

### GenesisFinalized

```solidity
Expand Down
21 changes: 19 additions & 2 deletions docs/root/RootERC20Predicate.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function exitHelper() external view returns (address)
### initialize

```solidity
function initialize(address newStateSender, address newExitHelper, address newChildERC20Predicate, address newChildTokenTemplate, address nativeTokenRootAddress) external nonpayable
function initialize(address newStateSender, address newExitHelper, address newChildERC20Predicate, address newChildTokenTemplate, address newNativeTokenRoot) external nonpayable
```

Initialization function for RootERC20Predicate
Expand All @@ -165,7 +165,7 @@ Initialization function for RootERC20Predicate
| newExitHelper | address | Address of ExitHelper to receive withdrawal information from |
| newChildERC20Predicate | address | Address of child ERC20 predicate to communicate with |
| newChildTokenTemplate | address | undefined |
| nativeTokenRootAddress | address | undefined |
| newNativeTokenRoot | address | undefined |

### mapToken

Expand All @@ -189,6 +189,23 @@ Function to be used for token mapping
|---|---|---|
| _0 | address | address Address of the child token |

### nativeTokenRoot

```solidity
function nativeTokenRoot() external view returns (address)
```

Function that retrieves rootchain token that represents Supernets native token




#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | address | address Address of rootchain token (mapped to Supernets native token) |

### onL2StateReceive

```solidity
Expand Down
58 changes: 57 additions & 1 deletion docs/root/staking/CustomSupernetManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ function acceptOwnership() external nonpayable
*The new owner accepts the ownership transfer.*


### addGenesisBalance

```solidity
function addGenesisBalance(uint256 amount) external nonpayable
```

addGenesisBalance is used to specify genesis balance information for genesis accounts on the Supernets. It is applicable only in case Supernets native contract is mapped to a pre-existing rootchain ERC20 token.



#### Parameters

| Name | Type | Description |
|---|---|---|
| amount | uint256 | represents the amount to be premined in the genesis. |

### domain

```solidity
Expand Down Expand Up @@ -60,6 +76,28 @@ finalizes initial genesis validator set
*only callable by owner*


### genesisBalances

```solidity
function genesisBalances(address) external view returns (uint256)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| _0 | address | undefined |

#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | uint256 | undefined |

### genesisSet

```solidity
Expand Down Expand Up @@ -119,7 +157,7 @@ function id() external view returns (uint256)
### initialize

```solidity
function initialize(address newStakeManager, address newBls, address newStateSender, address newMatic, address newChildValidatorSet, address newExitHelper, string newDomain) external nonpayable
function initialize(address newStakeManager, address newBls, address newStateSender, address newMatic, address newChildValidatorSet, address newExitHelper, address newRootERC20Predicate, string newDomain) external nonpayable
```


Expand All @@ -136,6 +174,7 @@ function initialize(address newStakeManager, address newBls, address newStateSen
| newMatic | address | undefined |
| newChildValidatorSet | address | undefined |
| newExitHelper | address | undefined |
| newRootERC20Predicate | address | undefined |
| newDomain | string | undefined |

### onInit
Expand Down Expand Up @@ -327,6 +366,23 @@ event AddedToWhitelist(address indexed validator)
|---|---|---|
| validator `indexed` | address | undefined |

### GenesisBalanceAdded

```solidity
event GenesisBalanceAdded(address indexed account, uint256 indexed amount)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| account `indexed` | address | undefined |
| amount `indexed` | uint256 | undefined |

### GenesisFinalized

```solidity
Expand Down
1 change: 1 addition & 0 deletions script/deployment/DeployNewRootContractSet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ contract DeployNewRootContractSet is
config.readAddress('["CustomSupernetManager"].newMatic'),
config.readAddress('["CustomSupernetManager"].newChildValidatorSet'),
exitHelperProxy,
config.readAddress('["CustomSupernetManager"].newRootERC20Predicate'),
config.readString('["CustomSupernetManager"].newDomain')
);
}
Expand Down
Loading
Loading