Skip to content

Commit

Permalink
Merge pull request #19 from persistenceOne/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
RohitAudit authored May 17, 2022
2 parents e965d6d + e8c483e commit f8a25b9
Show file tree
Hide file tree
Showing 17 changed files with 1,069 additions and 22,015 deletions.
41 changes: 34 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
# Advanced Sample Hardhat Project
# pSTAKE ETH Liquid Staking Protocol

This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem.
This project contains the contracts used by pSTAKE to implement the liquid staking protocol for ethereum POS system.

The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code.

Try running some of the following tasks:
### Contracts List

- **CORE CONTRACT:**
- **ISSUER CONTRACT:**
- **KEYSMANAGER CONTRACT:**
- **ORACLE CONTRACT:**
- **STAKING-POOL CONTRACT:**
- **STKETH CONTRACT:**
- **WITHDRAWAL CONTRACT:**
- **PERMISSION CONTRACT:**


### Steps to run the contracts

- **For testing**:
- npx hardhat test
- **For local deployment**:
- Start a local node: `npx hardhat node`
- Deploy the withdrawal contract: `npx hardhat run scripts/deploy_withdrawal.js --network localhost`
- Change the withdrawal address in deploy_test.js
- Deploy the contracts: `npx hardhat run scripts/deploy_test.js --network localhost`
- **For mainnet deployment**:
- Change .env file, add private key and enpoint
- Change variable for etherscan verification such as your etherscan API key
- Deploy the withdrawal contract: `npx hardhat run scripts/deploy_withdrawal.js --network mainnet`
- Change the withdrawal address in deploy_test.js
- Deploy the contracts: `npx hardhat run scripts/deploy.js --network mainnet`


**Various shell commands for hardhat development**
```shell
npx hardhat accounts
npx hardhat compile
Expand All @@ -15,8 +42,8 @@ npx hardhat node
npx hardhat help
REPORT_GAS=true npx hardhat test
npx hardhat coverage
npx hardhat run scripts/deploy.js
node scripts/deploy.js
npx hardhat run scripts/deploy_mainnet.js
node scripts/deploy_mainnet.js
npx eslint '**/*.js'
npx eslint '**/*.js' --fix
npx prettier '**/*.{json,sol,md}' --check
Expand All @@ -32,7 +59,7 @@ To try out Etherscan verification, you first need to deploy a contract to an Eth
In this project, copy the .env.example file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Ropsten node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract:

```shell
hardhat run --network ropsten scripts/deploy.js
hardhat run --network ropsten scripts/deploy_mainnet.js
```

Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command:
Expand Down
113 changes: 21 additions & 92 deletions contracts/Issuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,82 +5,63 @@ import "./CoreRef.sol";
import "./interfaces/IKeysManager.sol";
import "./interfaces/IDepositContract.sol";
import "./interfaces/IIssuer.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";

/// @author PStake
/// @title Issuer
/// @notice contract for issuance of StkEth
contract Issuer is CoreRef, IIssuer, ReentrancyGuard {
uint256 public constant VALIDATOR_DEPOSIT = 31e18;
uint256 public constant VERIFICATION_DEPOSIT = 1e18;

uint256 public constant BASIS_POINT = 10000;

IDepositContract public immutable DEPOSIT_CONTRACT;
uint256 public override pendingValidators;
uint256 public minActivatingDeposit;
uint256 public pendingValidatorsLimit;


mapping(address => mapping(uint256 => uint256)) public activations;
uint256 public ethStaked = 0;


/// @notice constructor for initializing core
/// @param core address of the core
/// @param _minActivatingDeposit minimum amount of ether deposited to activate ...
/// @param _pendingValidatorsLimit ...
/// @param _depositContract Deposit Contract address for Eth2
constructor(
address core,
uint256 _minActivatingDeposit,
uint256 _pendingValidatorsLimit,
address _depositContract
) CoreRef(core) {
require(_depositContract != address(0), "Issuer: Zero address");
DEPOSIT_CONTRACT = IDepositContract(_depositContract);
minActivatingDeposit = _minActivatingDeposit;

require(_pendingValidatorsLimit < BASIS_POINT, "Issuer: invalid limit");
pendingValidatorsLimit = _pendingValidatorsLimit;
}



/// @notice function returns minimum activating deposit.
/// @return minActivatingDeposit returns the value of minimum deposit required to activate validator.
function activatingDeposit()
public
view
returns (uint256)
{
return minActivatingDeposit;
}


/// @notice function returns pending validator limit.
/// @return pendingValidatorsLimit number of pending validators.
function pendingValidatorLimit()
public
view
returns (uint256)
public
view
returns (uint256)
{
return pendingValidatorsLimit;
}

function setMinActivatingDeposit(uint256 _minActivatingDeposit)
external
onlyGovernor
function ethStakedIssuer()
public override
view
returns (uint256)
{
minActivatingDeposit = _minActivatingDeposit;
emit SetMinActivationDeposit(_minActivatingDeposit);
return ethStaked;
}


/// @notice function for setting the count of pending validators limit.
/// @param _pendingValidatorsLimit integer limit for number of pending validators.
function setPendingValidatorsLimit(uint256 _pendingValidatorsLimit)
external
onlyGovernor
external
onlyGovernor
{
require(_pendingValidatorsLimit < BASIS_POINT, "Issuer: invalid limit");
pendingValidatorsLimit = _pendingValidatorsLimit;
Expand All @@ -91,8 +72,8 @@ contract Issuer is CoreRef, IIssuer, ReentrancyGuard {
/// @notice function for updating the count of pending validators with new activated validators.
/// @param newActiveValidators the number of new activated validators.
function updatePendingValidator(uint256 newActiveValidators)
external
override
external
override
{
require(
core().oracle() == msg.sender,
Expand All @@ -104,7 +85,6 @@ contract Issuer is CoreRef, IIssuer, ReentrancyGuard {
}



/// @notice function to mint Stk Eth for Eth.
/// @param amount amount of ether.
/// @param user address of user.
Expand All @@ -114,65 +94,14 @@ contract Issuer is CoreRef, IIssuer, ReentrancyGuard {
stkEth().mint(user, stkEthToMint);
}


/// @notice function for issuer to stake
function stake() public payable whenNotPaused {
require(msg.value > 0, "Issuer: can't stake zero");

if (msg.value <= minActivatingDeposit) {
mintStkEthForEth(msg.value, msg.sender);
return;
}

// mint tokens if current pending validators limit is not exceeded
uint256 _pendingValidators = pendingValidators +
((address(this).balance) / (VALIDATOR_DEPOSIT));
uint256 _activatedValidators = oracle().activatedValidators();
uint256 validatorIndex = _activatedValidators + _pendingValidators;


if (
validatorIndex * BASIS_POINT <=
_activatedValidators * (pendingValidatorsLimit + BASIS_POINT)
) {
// 10001
mintStkEthForEth(msg.value, msg.sender);

} else {

activations[msg.sender][validatorIndex] =
activations[msg.sender][validatorIndex] +
msg.value;
}
emit Stake(msg.sender, msg.value, block.timestamp);
ethStaked = ethStaked + msg.value;
mintStkEthForEth(msg.value, msg.sender);
}



/// @notice Mint stkEth after waiting for validator to get active
/// @param _account account of users whose stkEth need to be minted
/// @param _validatorIndex index of validator which got activated
function activate(address _account, uint256 _validatorIndex)
external
whenNotPaused
{
uint256 activatedValidators = oracle().activatedValidators();


uint256 amount = activations[_account][_validatorIndex];
require(amount > 0, "Issuer: invalid validator index");

require(
_validatorIndex * BASIS_POINT <=
activatedValidators * (pendingValidatorsLimit + BASIS_POINT),
"Issuer: validator is not active yet"
);

delete activations[_account][_validatorIndex];
mintStkEthForEth(amount, _account);
}



/// @notice function for deposit of 32 Ether.
/// @param publicKey public key of the validator.
function depositToEth2(bytes calldata publicKey) external {
Expand All @@ -186,7 +115,7 @@ contract Issuer is CoreRef, IIssuer, ReentrancyGuard {
IKeysManager(core().keysManager()).depositValidator(publicKey);

pendingValidators = pendingValidators + 1;
DEPOSIT_CONTRACT.deposit{value: VALIDATOR_DEPOSIT}(
DEPOSIT_CONTRACT.deposit{value : VALIDATOR_DEPOSIT}(
publicKey, //
abi.encodePacked(core().withdrawalCredential()),
validator.signature,
Expand All @@ -197,9 +126,9 @@ contract Issuer is CoreRef, IIssuer, ReentrancyGuard {

/// @notice function for sending 1 Ether to a node operator address.
/// @param nodeOperator address of the node operator
function withdrawalverificationDeposit(address nodeOperator) internal nonReentrant {
function withdrawalverificationDeposit(address nodeOperator) internal nonReentrant {

(bool sent, ) = nodeOperator.call{value: VERIFICATION_DEPOSIT }("");
(bool sent,) = nodeOperator.call{value : VERIFICATION_DEPOSIT}("");
require(sent, "Issuer: Failed to send to Node Operator");
}

Expand Down
Loading

0 comments on commit f8a25b9

Please sign in to comment.