Skip to content
This repository has been archived by the owner on May 22, 2023. It is now read-only.

ETH Delegating #483

Merged
merged 59 commits into from
Nov 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e63faeb
ETH bonding contract
nkuba Jun 17, 2020
32ee0d4
ETH staking contract
nkuba Jun 17, 2020
48f2384
Added tests for ETH bonding and staking contracts
nkuba Aug 7, 2020
865b0a4
Added todo about initialization period
nkuba Aug 11, 2020
d6ae3f7
Updated visibility to match abstract contract
nkuba Aug 19, 2020
531690b
Updated events emitted on ETH stake
nkuba Aug 19, 2020
4112c05
Renamed ETHBonding to EthBonding
nkuba Aug 19, 2020
3a5636c
Renamed ETHStaking to EthDelegating
nkuba Aug 19, 2020
f252f4f
Renamed stake to delegate
nkuba Aug 19, 2020
6c71cea
Renamed _from to owner
nkuba Aug 19, 2020
2479778
Expect contract typed addresses in constructors
nkuba Aug 19, 2020
c61e18c
Combined EthDelegating into EthBonding
nkuba Aug 19, 2020
07e5ddb
Added EthBonding to deployment script
nkuba Aug 19, 2020
a8f4489
Initialization period for ETH-only delegation
nkuba Aug 20, 2020
aab2b89
Require minimum ETH value passed on delegation
nkuba Aug 20, 2020
4a75c11
Added getDelegationInfo
nkuba Aug 20, 2020
b98050a
Renamed EthBonding to FullyBackedBonding
nkuba Sep 24, 2020
fd99459
Updated order of imports
nkuba Sep 24, 2020
6bf2f6a
Moved FullyBackedBonding contract to dedicated directory
nkuba Sep 24, 2020
04c8d25
Initial version of FullyBackedBondedECDSAKeep
nkuba Sep 24, 2020
7533b4a
Initial version of FullyBackedBondedECDSAKeepFactory
nkuba Sep 24, 2020
20c375e
Renamed EthBondingTest.js
nkuba Sep 24, 2020
81be402
Added unit tests for FullyBacked keep and bonding
nkuba Sep 25, 2020
7c3d0aa
Added fully backed contracts to migrations scripts
nkuba Sep 25, 2020
0079c13
Claim delegated authority in Fully Backed keep contract
nkuba Sep 25, 2020
d5d6703
Added missing import in Keep Factory contract
nkuba Sep 25, 2020
c2fc5ef
Minor improvements to docs
nkuba Sep 25, 2020
360486f
Lock bonding withdraw just after delegation
nkuba Sep 26, 2020
d65a096
Merge branch 'master' into eth-bonding
pdyraga Oct 27, 2020
742d3cf
Refer to the most recent pre versions of keep dependencies
pdyraga Oct 27, 2020
a9cb6f3
Project version for contracts set to 1.3.0-pre.0
pdyraga Oct 27, 2020
80c6e49
Revert "Expect contract typed addresses in constructors"
nkuba Oct 29, 2020
26eea9d
Removed comment about clone removal
nkuba Oct 29, 2020
cc58f14
Renamed FullyBackedBondedECDSAKeep to FullyBackedECDSAKeep
nkuba Oct 29, 2020
1e088d8
Confirmed bondWeightDivisor to 1 ETH
nkuba Oct 29, 2020
c04038b
Increased DELEGATION_LOCK_PERIOD to 2 weeks
nkuba Oct 29, 2020
c8dc76e
Updated delegation lock period hardcoded in test
nkuba Oct 29, 2020
85c3663
Include delegation value in OperatorDelegated event
nkuba Oct 30, 2020
566cc48
Set minimum delegation deposit to 40 ETH
nkuba Oct 30, 2020
a1ea59b
Decided on 20 ETH as minimum bond value
nkuba Oct 30, 2020
e4c9d82
Improved time increase value in test
nkuba Oct 30, 2020
ff5008c
Updated delegation lock period to 12 hours
nkuba Oct 30, 2020
0c0475a
Improved docs around fully backed bonding
nkuba Oct 30, 2020
ae34de4
Cleaned up truffle deploy script
nkuba Oct 30, 2020
25c6a4d
Assert createdAt and undelegatedAt in delegation test
nkuba Oct 30, 2020
faca5bd
Cleaned truffle init script
nkuba Oct 30, 2020
03daf5f
Removed not used addKeep function from test stubs
nkuba Oct 30, 2020
196880a
Improved time increase margin in tests
nkuba Oct 30, 2020
d1edab3
Merge remote-tracking branch 'origin/master' into eth-bonding
nkuba Oct 30, 2020
ee9a30b
Removed not needed TODO comment in test
nkuba Nov 2, 2020
65186c9
Very minor improvements to tests
nkuba Nov 2, 2020
b92218c
Get delegation lock period from contract in tests
nkuba Nov 2, 2020
766a841
Removed not needed call in initialization script
nkuba Nov 2, 2020
8a4ff82
Defined ini period in truffle deployment script
nkuba Nov 2, 2020
3778ae1
Added tests for operator updates
nkuba Nov 2, 2020
cf0127c
Added top up function to Fully Backed Bonding contract
nkuba Nov 2, 2020
102ce15
Fixed failing test
nkuba Nov 2, 2020
dc04021
Replaced before with beforeEach for topUp test
nkuba Nov 2, 2020
f9f719a
Added details to topup documentation
nkuba Nov 2, 2020
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: 1 addition & 2 deletions solidity/contracts/BondedECDSAKeep.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import "@keep-network/keep-core/contracts/TokenStaking.sol";
/// @title Bonded ECDSA Keep
/// @notice ECDSA keep with additional signer bond requirement.
/// @dev This contract is used as a master contract for clone factory in
/// BondedECDSAKeepFactory as per EIP-1167. It should never be removed after
/// initial deployment as this will break functionality for all created clones.
/// BondedECDSAKeepFactory as per EIP-1167.
contract BondedECDSAKeep is AbstractBondedECDSAKeep {
// Stake that was required from each keep member on keep creation.
// The value is used for keep members slashing.
Expand Down
210 changes: 210 additions & 0 deletions solidity/contracts/fully-backed/FullyBackedBonding.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/**
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓

Trust math, not hardware.
*/

pragma solidity 0.5.17;

import "../AbstractBonding.sol";

import "@keep-network/keep-core/contracts/Authorizations.sol";
import "@keep-network/keep-core/contracts/StakeDelegatable.sol";
import "@keep-network/keep-core/contracts/KeepRegistry.sol";

import "@keep-network/sortition-pools/contracts/api/IFullyBackedBonding.sol";

/// @title Fully Backed Bonding
/// @notice Contract holding deposits and delegations for ETH-only keeps'
/// operators. An owner of the ETH can delegate ETH to an operator by depositing
/// it in this contract.
contract FullyBackedBonding is
IFullyBackedBonding,
AbstractBonding,
Authorizations,
StakeDelegatable
{
event Delegated(address indexed owner, address indexed operator);

event OperatorDelegated(
address indexed operator,
address indexed beneficiary,
address indexed authorizer,
uint256 value
);

event OperatorToppedUp(address indexed operator, uint256 value);

// The ether value (in wei) that should be passed along with the delegation
// and deposited for bonding.
uint256 public constant MINIMUM_DELEGATION_DEPOSIT = 40 ether;

// Once a delegation to an operator is received the delegator has to wait for
// specific time period before being able to pull out the funds.
uint256 public constant DELEGATION_LOCK_PERIOD = 12 hours;

uint256 public initializationPeriod; // varies between mainnet and testnet

/// @notice Initializes Fully Backed Bonding contract.
/// @param _keepRegistry Keep Registry contract address.
/// @param _initializationPeriod To avoid certain attacks on group selection,
/// recently delegated operators must wait for a specific period of time
/// before being eligible for group selection.
constructor(KeepRegistry _keepRegistry, uint256 _initializationPeriod)
public
AbstractBonding(address(_keepRegistry))
Authorizations(_keepRegistry)
{
initializationPeriod = _initializationPeriod;
}

/// @notice Registers delegation details. The function is used to register
/// addresses of operator, beneficiary and authorizer for a delegation from
/// the caller.
/// The function requires ETH to be submitted in the call as a protection
/// against attacks blocking operators. The value should be at least equal
/// to the minimum delegation deposit. Whole amount is deposited as operator's
/// unbonded value for the future bonding.
/// @param operator Address of the operator.
/// @param beneficiary Address of the beneficiary.
/// @param authorizer Address of the authorizer.
function delegate(
address operator,
address payable beneficiary,
address authorizer
) external payable {
address owner = msg.sender;

require(
operators[operator].owner == address(0),
"Operator already in use"
);

require(
msg.value >= MINIMUM_DELEGATION_DEPOSIT,
"Insufficient delegation value"
);

operators[operator] = Operator(
OperatorParams.pack(0, block.timestamp, 0),
owner,
beneficiary,
authorizer
);

deposit(operator);

emit Delegated(owner, operator);
emit OperatorDelegated(operator, beneficiary, authorizer, msg.value);
}

/// @notice Top-ups operator's unbonded value.
/// @dev This function should be used to add new unbonded value to the system
/// for an operator. The `deposit` function defined in parent abstract contract
/// should be called only by applications returning value that has been already
/// initially deposited and seized later. As an application may seize bonds
/// and return them to the bonding contract with `deposit` function it makes
/// tracking the totally deposited value much more complicated. Functions
/// `delegate` and `topUps` should be used to add fresh value to the contract
/// and events emitted by these functions should be enough to determine total
/// value deposited ever for an operator.
/// @param operator Address of the operator.
function topUp(address operator) public payable {
deposit(operator);

emit OperatorToppedUp(operator, msg.value);
}

pdyraga marked this conversation as resolved.
Show resolved Hide resolved
/// @notice Checks if the operator for the given bond creator contract
/// has passed the initialization period.
/// @param operator The operator address.
/// @param bondCreator The bond creator contract address.
/// @return True if operator has passed initialization period for given
/// bond creator contract, false otherwise.
function isInitialized(address operator, address bondCreator)
public
view
returns (bool)
{
uint256 operatorParams = operators[operator].packedParams;

return
isAuthorizedForOperator(operator, bondCreator) &&
_isInitialized(operatorParams);
}

/// @notice Withdraws amount from operator's value available for bonding.
/// This function can be called only by:
/// - operator,
/// - owner of the stake.
/// Withdraw cannot be performed immediately after delegation to protect
/// from a griefing. It is required that delegator waits specific period
/// of time before they can pull out the funds deposited on delegation.
/// @param amount Value to withdraw in wei.
/// @param operator Address of the operator.
function withdraw(uint256 amount, address operator) public {
require(
msg.sender == operator || msg.sender == ownerOf(operator),
"Only operator or the owner is allowed to withdraw bond"
);

require(
hasDelegationLockPassed(operator),
"Delegation lock period has not passed yet"
);

withdrawBond(amount, operator);
}

/// @notice Gets delegation info for the given operator.
/// @param operator Address of the operator.
/// @return createdAt The time when the delegation was created.
/// @return undelegatedAt The time when undelegation has been requested.
/// If undelegation has not been requested, 0 is returned.
function getDelegationInfo(address operator)
public
view
returns (uint256 createdAt, uint256 undelegatedAt)
{
uint256 operatorParams = operators[operator].packedParams;

return (
operatorParams.getCreationTimestamp(),
operatorParams.getUndelegationTimestamp()
);
}

/// @notice Is the operator with the given params initialized
function _isInitialized(uint256 operatorParams)
internal
view
returns (bool)
{
return
block.timestamp >
operatorParams.getCreationTimestamp().add(initializationPeriod);
}

/// @notice Has lock period passed for a delegation.
/// @param operator Address of the operator.
/// @return True if delegation lock period passed, false otherwise.
function hasDelegationLockPassed(address operator)
internal
view
returns (bool)
{
return
block.timestamp >
operators[operator].packedParams.getCreationTimestamp().add(
DELEGATION_LOCK_PERIOD
);
}
}
70 changes: 70 additions & 0 deletions solidity/contracts/fully-backed/FullyBackedECDSAKeep.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓

Trust math, not hardware.
*/

pragma solidity 0.5.17;

import "../AbstractBondedECDSAKeep.sol";
import "./FullyBackedBonding.sol";
import "./FullyBackedECDSAKeepFactory.sol";

/// @title Fully Backed Bonded ECDSA Keep
/// @notice ECDSA keep with additional signer bond requirement that is fully backed
/// by ETH only.
/// @dev This contract is used as a master contract for clone factory in
/// BondedECDSAKeepFactory as per EIP-1167.
contract FullyBackedECDSAKeep is AbstractBondedECDSAKeep {
FullyBackedBonding bonding;
FullyBackedECDSAKeepFactory keepFactory;

/// @notice Initialization function.
/// @dev We use clone factory to create new keep. That is why this contract
/// doesn't have a constructor. We provide keep parameters for each instance
/// function after cloning instances from the master contract.
/// @param _owner Address of the keep owner.
/// @param _members Addresses of the keep members.
/// @param _honestThreshold Minimum number of honest keep members.
/// @param _bonding Address of the Bonding contract.
/// @param _keepFactory Address of the BondedECDSAKeepFactory that created
/// this keep.
function initialize(
address _owner,
address[] memory _members,
uint256 _honestThreshold,
address _bonding,
address payable _keepFactory
) public {
super.initialize(_owner, _members, _honestThreshold, _bonding);

bonding = FullyBackedBonding(_bonding);
keepFactory = FullyBackedECDSAKeepFactory(_keepFactory);

bonding.claimDelegatedAuthority(_keepFactory);
}

function slashForSignatureFraud() internal {
// TODO: We don't need to do anything as keep owner is able to seize the bonds
// TODO: Ban members (remove from sortition pool and don't let to rejoin)
}

/// @notice Gets the beneficiary for the specified member address.
/// @param _member Member address.
/// @return Beneficiary address.
function beneficiaryOf(address _member)
internal
view
returns (address payable)
{
return bonding.beneficiaryOf(_member);
}
}
Loading