Skip to content

Commit

Permalink
Implement migration of solo stakers to staking pools
Browse files Browse the repository at this point in the history
  • Loading branch information
DrZoltanFazekas committed Dec 13, 2024
1 parent 6b7841c commit d303686
Show file tree
Hide file tree
Showing 9 changed files with 508 additions and 162 deletions.
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,26 @@ forge script script/commission_Delegation.s.sol --rpc-url http://localhost:4201
using `same` for the second argument to leave the commission percentage unchanged and `true` for the third argument. Replacing the second argument with `same` and the third argument with `false` only displays the current commission rate.


## Validator Activation
If your node's account has enough ZIL for the minimum stake required, you can activate your node as a validator with a deposit of e.g. 10 million ZIL. Run
## Validator Activation and Migration
If your node has already been activated as a validator i.e. solo staker, you can migrate it to a staking pool. Run
```bash
cast send --legacy --rpc-url http://localhost:4201 --private-key 0x... \
0x00000000005a494c4445504f53495450524f5859 "setControlAddress(bytes,address)" \
0x92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c \
0x7A0b7e6D24eDe78260c9ddBD98e828B0e11A8EA2
```
using the private key you used to deposit your nodes, the BLS public key of your node and the address of your delegation contract. Afterwards run
```bash
cast send --legacy --rpc-url http://localhost:4201 --private-key $PRIVATE_KEY \
0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2 "migrate(bytes)" \
0x92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c
```
using the BLS public key of your node.

If your node hasn't been deposited yet but the owner account has enough ZIL for the minimum stake required, you can activate your node as a validator with a deposit of e.g. 10 million ZIL. Run
```bash
cast send --legacy --value 10000000ether --rpc-url http://localhost:4201 --private-key $PRIVATE_KEY \
0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2 "deposit(bytes,bytes,bytes)" \
0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2 "depositFirst(bytes,bytes,bytes)" \
0x92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c \
0x002408011220d5ed74b09dcbe84d3b32a56c01ab721cf82809848b6604535212a219d35c412f \
0xb14832a866a49ddf8a3104f8ee379d29c136f29aeb8fccec9d7fb17180b99e8ed29bee2ada5ce390cb704bc6fd7f5ce814f914498376c4b8bc14841a57ae22279769ec8614e2673ba7f36edc5a4bf5733aa9d70af626279ee2b2cde939b4bd8a
Expand All @@ -137,10 +152,10 @@ with the BLS public key, the peer id and the BLS signature of your node. Note th

Note that the reward address registered for your validator node will be the address of the delegation contract (the proxy contract to be more precise).

Alternatively, you can proceed to the next section and delegate stake until the contract's balance reaches the 10 million ZIL minimum stake required for the activation, and then run
Alternatively, you can proceed to the next section and accept delegated stake until the contract's balance reaches the minimum stake required for the activation, and then run
```bash
cast send --legacy --rpc-url http://localhost:4201 --private-key $PRIVATE_KEY \
0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2 "deposit2(bytes,bytes,bytes)" \
0x7a0b7e6d24ede78260c9ddbd98e828b0e11a8ea2 "depositLater(bytes,bytes,bytes)" \
0x92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c \
0x002408011220d5ed74b09dcbe84d3b32a56c01ab721cf82809848b6604535212a219d35c412f \
0xb14832a866a49ddf8a3104f8ee379d29c136f29aeb8fccec9d7fb17180b99e8ed29bee2ada5ce390cb704bc6fd7f5ce814f914498376c4b8bc14841a57ae22279769ec8614e2673ba7f36edc5a4bf5733aa9d70af626279ee2b2cde939b4bd8a
Expand Down
17 changes: 15 additions & 2 deletions src/BaseDelegation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ abstract contract BaseDelegation is Delegation, PausableUpgradeable, Ownable2Ste

function _authorizeUpgrade(address newImplementation) internal onlyOwner virtual override {}

function _migrate(bytes calldata blsPubKey) internal onlyOwner virtual {
BaseDelegationStorage storage $ = _getBaseDelegationStorage();
require(!_isActivated() && address(this).balance == 0, "validator can not be migrated");
$.blsPubKey = blsPubKey;
(bool success, bytes memory data) = DEPOSIT_CONTRACT.call(abi.encodeWithSignature("getPeerId(bytes)", blsPubKey));
require(success, "peer id could not be retrieved");
$.peerId = data;
(success, ) = DEPOSIT_CONTRACT.call(abi.encodeWithSignature("setRewardAddress(bytes,address)", blsPubKey, address(this)));
require(success, "reward address could not be changed");
}

function migrate(bytes calldata blsPubKey) public virtual;

function _deposit(
bytes calldata blsPubKey,
bytes calldata peerId,
Expand All @@ -123,13 +136,13 @@ abstract contract BaseDelegation is Delegation, PausableUpgradeable, Ownable2Ste
require(success, "deposit failed");
}

function deposit(
function depositFirst(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
) public virtual payable;

function deposit2(
function depositLater(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
Expand Down
20 changes: 12 additions & 8 deletions src/LiquidDelegation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,26 @@ contract LiquidDelegation is BaseDelegation, ILiquidDelegation {
return $.lst;
}

function deposit(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
function depositFirst(
bytes calldata,
bytes calldata,
bytes calldata
) public override payable {
revert("not implemented");
}

function deposit2(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
function depositLater(
bytes calldata,
bytes calldata,
bytes calldata
) public override {
revert("not implemented");
}

function migrate(bytes calldata) public override {
revert("not implemented");
}

function stake() external override payable {
revert("not implemented");
}
Expand Down
23 changes: 16 additions & 7 deletions src/LiquidDelegationV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ contract LiquidDelegationV2 is BaseDelegation, ILiquidDelegation {
$.taxedRewards += msg.value;
}

// called by the node's account that deployed this contract and is its owner
// to request the node's activation as a validator using the delegated stake
function deposit2(
// called by the node's owner who deployed this contract
// to turn the already deposited validator node into a staking pool
function migrate(bytes calldata blsPubKey) public override onlyOwner {
_migrate(blsPubKey);
LiquidDelegationStorage storage $ = _getLiquidDelegationStorage();
require(NonRebasingLST($.lst).totalSupply() == 0, "stake already delegated");
NonRebasingLST($.lst).mint(owner(), getStake());
}

// called by the node's owner who deployed this contract
// to deposit the node as a validator using the delegated stake
function depositLater(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
Expand All @@ -60,10 +69,10 @@ contract LiquidDelegationV2 is BaseDelegation, ILiquidDelegation {
);
}

// called by the node's account that deployed this contract and is its owner
// with at least the minimum stake to request the node's activation as a validator
// before any stake is delegated to it
function deposit(
// called by the node's owner who deployed this contract
// with at least the minimum stake to deposit the node
// as a validator before any stake is delegated to it
function depositFirst(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
Expand Down
20 changes: 12 additions & 8 deletions src/NonLiquidDelegation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,26 @@ contract NonLiquidDelegation is BaseDelegation, INonLiquidDelegation {
__BaseDelegation_init(initialOwner);
}

function deposit(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
function depositFirst(
bytes calldata,
bytes calldata,
bytes calldata
) public override payable {
revert("not implemented");
}

function deposit2(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
function depositLater(
bytes calldata,
bytes calldata,
bytes calldata
) public override {
revert("not implemented");
}

function migrate(bytes calldata) public override {
revert("not implemented");
}

function stake() external payable override {
revert("not implemented");
}
Expand Down
25 changes: 18 additions & 7 deletions src/NonLiquidDelegationV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,20 @@ contract NonLiquidDelegationV2 is BaseDelegation, INonLiquidDelegation {

event RewardPaid(address indexed delegator, uint256 reward);

// called by the node's account that deployed this contract and is its owner
// to request the node's activation as a validator using the delegated stake
function deposit2(
// called by the node's owner who deployed this contract
// to turn the already deposited validator node into a staking pool
function migrate(bytes calldata blsPubKey) public override onlyOwner {
_migrate(blsPubKey);
NonLiquidDelegationStorage storage $ = _getNonLiquidDelegationStorage();
require($.stakings.length == 0, "stake already delegated");
// the owner's deposit must also be recorded as staking otherwise
// the owner would not benefit from the rewards accrued by the deposit
_append(int256(getStake()));
}

// called by the node's owner who deployed this contract
// to deposit the node as a validator using the delegated stake
function depositLater(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
Expand All @@ -129,10 +140,10 @@ contract NonLiquidDelegationV2 is BaseDelegation, INonLiquidDelegation {
);
}

// called by the node's account that deployed this contract and is its owner
// with at least the minimum stake to request the node's activation as a validator
// before any stake is delegated to it
function deposit(
// called by the node's owner who deployed this contract
// with at least the minimum stake to deposit the node
// as a validator before any stake is delegated to it
function depositFirst(
bytes calldata blsPubKey,
bytes calldata peerId,
bytes calldata signature
Expand Down
34 changes: 32 additions & 2 deletions test/BaseDelegation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,36 @@ abstract contract BaseDelegationTest is Test {
vm.stopPrank();
}

enum DepositMode {DepositThenStake, StakeThenDeposit, DepositThenMigrate}

function migrate(
BaseDelegation delegation,
uint256 depositAmount
) internal {
vm.deal(owner, owner.balance + depositAmount);
vm.startPrank(owner);

Deposit(delegation.DEPOSIT_CONTRACT()).deposit{
value: depositAmount
}(
bytes(hex"92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c"),
bytes(hex"002408011220d5ed74b09dcbe84d3b32a56c01ab721cf82809848b6604535212a219d35c412f"),
bytes(hex"b14832a866a49ddf8a3104f8ee379d29c136f29aeb8fccec9d7fb17180b99e8ed29bee2ada5ce390cb704bc6fd7f5ce814f914498376c4b8bc14841a57ae22279769ec8614e2673ba7f36edc5a4bf5733aa9d70af626279ee2b2cde939b4bd8a"),
address(0x0)
);

Deposit(delegation.DEPOSIT_CONTRACT()).setControlAddress(
bytes(hex"92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c"),
address(delegation)
);

delegation.migrate(
bytes(hex"92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c")
);

vm.stopPrank();
}

function deposit(
BaseDelegation delegation,
uint256 depositAmount,
Expand All @@ -142,7 +172,7 @@ abstract contract BaseDelegationTest is Test {
vm.deal(owner, owner.balance + depositAmount);
vm.startPrank(owner);

delegation.deposit{
delegation.depositFirst{
value: depositAmount
}(
bytes(hex"92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c"),
Expand Down Expand Up @@ -172,7 +202,7 @@ abstract contract BaseDelegationTest is Test {

vm.startPrank(owner);

delegation.deposit2(
delegation.depositLater(
bytes(hex"92fbe50544dce63cfdcc88301d7412f0edea024c91ae5d6a04c7cd3819edfc1b9d75d9121080af12e00f054d221f876c"),
bytes(hex"002408011220d5ed74b09dcbe84d3b32a56c01ab721cf82809848b6604535212a219d35c412f"),
bytes(hex"b14832a866a49ddf8a3104f8ee379d29c136f29aeb8fccec9d7fb17180b99e8ed29bee2ada5ce390cb704bc6fd7f5ce814f914498376c4b8bc14841a57ae22279769ec8614e2673ba7f36edc5a4bf5733aa9d70af626279ee2b2cde939b4bd8a")
Expand Down
Loading

0 comments on commit d303686

Please sign in to comment.