Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Refresh the minimum bondable value #714

Merged
merged 16 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 1 addition & 5 deletions solidity/contracts/deposit/Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,6 @@ contract Deposit is DepositFactoryAuthority {
/// `FeeRebateToken`.
/// @param _vendingMachineAddress `VendingMachine` address. More info in
/// `VendingMachine`.
/// @param _m Signing group honesty threshold.
/// @param _n Signing group size.
/// @param _lotSizeSatoshis The minimum amount of satoshi the funder is
/// required to send. This is also the amount of
/// TBTC the TDT holder will be eligible to mint:
Expand All @@ -594,16 +592,14 @@ contract Deposit is DepositFactoryAuthority {
IERC721 _tbtcDepositToken,
FeeRebateToken _feeRebateToken,
address _vendingMachineAddress,
uint16 _m,
uint16 _n,
uint64 _lotSizeSatoshis
) public onlyFactory payable {
self.tbtcSystem = _tbtcSystem;
self.tbtcToken = _tbtcToken;
self.tbtcDepositToken = _tbtcDepositToken;
self.feeRebateToken = _feeRebateToken;
self.vendingMachineAddress = _vendingMachineAddress;
self.initialize(_m, _n, _lotSizeSatoshis);
self.initialize(_lotSizeSatoshis);
}

/// @notice This function can only be called by the vending machine.
Expand Down
12 changes: 2 additions & 10 deletions solidity/contracts/deposit/DepositFunding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,21 @@ library DepositFunding {
/// @dev If called directly, the transaction will revert since the call will
/// be executed on an already set-up instance.
/// @param _d Deposit storage pointer.
/// @param _m Signing group honesty threshold.
/// @param _n Signing group size.
/// @param _lotSizeSatoshis Lot size in satoshis.
function initialize(
DepositUtils.Deposit storage _d,
uint16 _m,
uint16 _n,
uint64 _lotSizeSatoshis
) public {
require(_d.tbtcSystem.getAllowNewDeposits(), "New deposits aren't allowed.");
require(_d.inStart(), "Deposit setup already requested");
require(_d.tbtcSystem.isAllowedLotSize(_lotSizeSatoshis), "provided lot size not supported");

_d.lotSizeSatoshis = _lotSizeSatoshis;
uint256 _bondRequirementSatoshi = _lotSizeSatoshis.mul(_d.tbtcSystem.getInitialCollateralizedPercent()).div(100);
uint256 _bondRequirementWei = _d.fetchBitcoinPrice().mul(_bondRequirementSatoshi);

_d.keepSetupFee = _d.tbtcSystem.getNewDepositFeeEstimate();

/* solium-disable-next-line value-in-payable */
_d.keepAddress = _d.tbtcSystem.requestNewKeep.value(msg.value)(
_m,
_n,
_bondRequirementWei,
_lotSizeSatoshis,
TBTCConstants.getDepositTerm()
);

Expand Down
2 changes: 1 addition & 1 deletion solidity/contracts/interfaces/ITBTCSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ITBTCSystem {
function getNewDepositFeeEstimate() external view returns (uint256);
function getAllowNewDeposits() external view returns (bool);
function isAllowedLotSize(uint64 _lotSizeSatoshis) external view returns (bool);
function requestNewKeep(uint256 _m, uint256 _n, uint256 _bond, uint256 _maxSecuredLifetime) external payable returns (address);
function requestNewKeep(uint64 _lotSizeSatoshis, uint256 _maxSecuredLifetime) external payable returns (address);
function getSignerFeeDivisor() external view returns (uint16);
function getInitialCollateralizedPercent() external view returns (uint16);
function getUndercollateralizedThresholdPercent() external view returns (uint16);
Expand Down
12 changes: 1 addition & 11 deletions solidity/contracts/proxy/DepositFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ contract DepositFactory is CloneFactory, TBTCSystemAuthority{
TBTCToken public tbtcToken;
FeeRebateToken public feeRebateToken;
address public vendingMachineAddress;
uint16 public keepThreshold;
uint16 public keepSize;

constructor(address _systemAddress)
TBTCSystemAuthority(_systemAddress)
Expand All @@ -39,26 +37,20 @@ contract DepositFactory is CloneFactory, TBTCSystemAuthority{
/// @param _tbtcDepositToken TBTC Deposit Token contract.
/// @param _feeRebateToken AFee Rebate Token contract.
/// @param _vendingMachineAddress Address of the Vending Machine contract.
/// @param _keepThreshold Minimum number of honest keep members.
/// @param _keepSize Number of all members in a keep.
function setExternalDependencies(
address payable _masterDepositAddress,
TBTCSystem _tbtcSystem,
TBTCToken _tbtcToken,
TBTCDepositToken _tbtcDepositToken,
FeeRebateToken _feeRebateToken,
address _vendingMachineAddress,
uint16 _keepThreshold,
uint16 _keepSize
address _vendingMachineAddress
) public onlyTbtcSystem {
masterDepositAddress = _masterDepositAddress;
tbtcDepositToken = _tbtcDepositToken;
tbtcSystem = _tbtcSystem;
tbtcToken = _tbtcToken;
feeRebateToken = _feeRebateToken;
vendingMachineAddress = _vendingMachineAddress;
keepThreshold = _keepThreshold;
keepSize = _keepSize;
}

event DepositCloneCreated(address depositCloneAddress);
Expand Down Expand Up @@ -87,8 +79,6 @@ contract DepositFactory is CloneFactory, TBTCSystemAuthority{
tbtcDepositToken,
feeRebateToken,
vendingMachineAddress,
keepThreshold,
keepSize,
_lotSizeSatoshis
);

Expand Down
30 changes: 29 additions & 1 deletion solidity/contracts/system/KeepFactorySelection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ library KeepFactorySelection {
function initialize(
Storage storage _self,
IBondedECDSAKeepFactory _defaultFactory
) internal {
) public {
require(
address(_self.keepStakeFactory) == address(0),
"Already initialized"
Expand Down Expand Up @@ -89,6 +89,34 @@ library KeepFactorySelection {
return factory;
}

/// @notice Sets the minimum bondable value required from the operator to
/// join the sortition pool for tBTC.
/// @param _minimumBondableValue The minimum bond value the application
/// requires from a single keep.
/// @param _groupSize Number of signers in the keep.
/// @param _honestThreshold Minimum number of honest keep signers.
function setMinimumBondableValue(
Storage storage _self,
uint256 _minimumBondableValue,
uint256 _groupSize,
uint256 _honestThreshold
) public {
if (address(_self.keepStakeFactory) != address(0)) {
_self.keepStakeFactory.setMinimumBondableValue(
_minimumBondableValue,
_groupSize,
_honestThreshold
);
}
if (address(_self.ethStakeFactory) != address(0)) {
_self.ethStakeFactory.setMinimumBondableValue(
_minimumBondableValue,
_groupSize,
_honestThreshold
);
}
}

/// @notice Refreshes the keep factory choice. If either ETH-stake factory
/// or selection strategy is not set, KEEP-stake factory is selected.
/// Otherwise, calls selection strategy providing addresses of both
Expand Down
115 changes: 78 additions & 37 deletions solidity/contracts/system/TBTCSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {

KeepFactorySelection.Storage keepFactorySelection;

uint16 public keepSize;
uint16 public keepThreshold;

// Parameters governed by the TBTCSystem owner
bool private allowNewDeposits = false;
uint16 private signerFeeDivisor = 2000; // 1/2000 == 5bps == 0.05% == 0.0005
Expand Down Expand Up @@ -124,6 +127,8 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
require(initializedTimestamp == 0, "already initialized");

keepFactorySelection.initialize(_defaultKeepFactory);
keepThreshold = _keepThreshold;
keepSize = _keepSize;

_vendingMachine.setExternalAddresses(
_tbtcToken,
Expand All @@ -136,9 +141,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
_tbtcToken,
_tbtcDepositToken,
_feeRebateToken,
address(_vendingMachine),
_keepThreshold,
_keepSize
address(_vendingMachine)
);
setTbtcDepositToken(_tbtcDepositToken);
initializedTimestamp = block.timestamp;
Expand All @@ -151,16 +154,16 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
return allowNewDeposits;
}

/// @notice Return the lowest lot size currently enabled for deposits.
/// @return The lowest lot size, in satoshis.
function getMinimumLotSize() public view returns (uint256) {
return lotSizesSatoshis[0];
}

/// @notice Return the largest lot size currently enabled for deposits.
/// @return The largest lot size, in satoshis.
function getMaxLotSize() public view returns (uint256) {
uint256 max = 0;
for (uint i = 0; i<lotSizesSatoshis.length; i++) {
if (lotSizesSatoshis[i] > max) {
max = lotSizesSatoshis[i];
}
}
return max;
function getMaximumLotSize() public view returns (uint256) {
return lotSizesSatoshis[lotSizesSatoshis.length - 1];
}

/// @notice One-time-use emergency function to disallow future deposit creation for 10 days.
Expand Down Expand Up @@ -213,7 +216,8 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
/// @notice Set the allowed deposit lot sizes.
/// @dev Lot size array should always contain 10**8 satoshis (1 BTC) and
/// cannot contain values less than 50000 satoshis (0.0005 BTC) or
/// greater than 10**10 satoshis (100 BTC).
/// greater than 10**10 satoshis (100 BTC). Lot size array must not
/// have duplicates and it must be sorted.
/// This can be finalized by calling `finalizeLotSizesUpdate`
/// anytime after `governanceTimeDelay` has elapsed.
/// @param _lotSizes Array of allowed lot sizes.
Expand All @@ -230,6 +234,10 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
} else if (_lotSizes[i] > 10 * 10**9) {
// Failed the maximum requirement, break on out.
revert("Lot sizes greater than 100 BTC are not allowed");
} else if (i > 0 && _lotSizes[i] == _lotSizes[i-1]) {
revert("Lot size array must not have duplicates");
} else if (i > 0 && _lotSizes[i] < _lotSizes[i-1]) {
revert("Lot size array must be sorted");
}
}

Expand Down Expand Up @@ -377,6 +385,8 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
emit LotSizesUpdated(newLotSizesSatoshis);
lotSizesChangeInitiated = 0;
newLotSizesSatoshis.length = 0;

refreshMinimumBondableValue();
}

/// @notice Finish setting the system collateralization levels
Expand Down Expand Up @@ -468,18 +478,6 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
return lotSizesSatoshis;
}

/// @notice Check if a lot size is allowed.
/// @param _lotSizeSatoshis Lot size to check.
/// @return True if lot size is allowed, false otherwise.
function isAllowedLotSize(uint64 _lotSizeSatoshis) external view returns (bool){
for( uint i = 0; i < lotSizesSatoshis.length; i++){
if (lotSizesSatoshis[i] == _lotSizeSatoshis){
return true;
}
}
return false;
}

/// @notice Get the system undercollateralization level for new deposits
function getUndercollateralizedThresholdPercent() external view returns (uint16) {
return undercollateralizedThresholdPercent;
Expand All @@ -506,13 +504,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
"Caller must be a Deposit contract"
);

uint256 price = priceFeed.getPrice();
if (price == 0 || price > 10 ** 18) {
// This is if a sat is worth 0 wei, or is worth >1 ether. Revert at
// once.
revert("System returned a bad price");
}
return price;
return _fetchBitcoinPrice();
}

// Difficulty Oracle
Expand Down Expand Up @@ -566,6 +558,20 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
);
}

/// @notice Refreshes the minimum bondable value required from the operator
/// to join the sortition pool for tBTC. The minimum bondable value is
/// equal to the current minimum lot size collateralized 150% multiplied by
/// the current BTC price.
/// @dev It is recommended to call this function on tBTC initialization and
/// after minimum lot size update.
function refreshMinimumBondableValue() public {
keepFactorySelection.setMinimumBondableValue(
calculateBondRequirementWei(getMinimumLotSize()),
keepSize,
keepThreshold
);
}

/// @notice Returns the time delay used for governance actions except for
/// price feed additions.
function getGovernanceTimeDelay() public pure returns (uint256) {
Expand All @@ -590,23 +596,58 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
}

/// @notice Request a new keep opening.
/// @param _m Minimum number of honest keep members required to sign.
/// @param _n Number of members in the keep.
/// @param _lotSizeSatoshis Lot size in satoshis.
/// @param _maxSecuredLifetime Duration of stake lock in seconds.
/// @return Address of a new keep.
function requestNewKeep(
uint256 _m,
uint256 _n,
uint256 _bond,
uint64 _lotSizeSatoshis,
Copy link
Contributor

Choose a reason for hiding this comment

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

Well now I feel weird about this taking the lot size 🤔

I think it's a marked improvement though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, it feels quite natural to me but I don't have the full context. Deposit is initialized with the lot size and TBTCSystem does want to work with supported lot sizes. The moment we open a keep is where lot sizes ends and wei bonds come into play.

Copy link
Contributor

Choose a reason for hiding this comment

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

It feels like by the time we reach the concept of a keep, we should be requesting the keep with a particular bond for the keep, rather than passing the lot size. But I like that the price feed and bond calculation is here now. So I'm still a little ways away from figuring out what's bothering me about it :) Regardless, I don't think it's worth doing anything more here for now.

uint256 _maxSecuredLifetime
)
external
payable
returns (address)
{
require(tbtcDepositToken.exists(uint256(msg.sender)), "Caller must be a Deposit contract");
require(isAllowedLotSize(_lotSizeSatoshis), "provided lot size not supported");

IBondedECDSAKeepFactory _keepFactory = keepFactorySelection.selectFactoryAndRefresh();
return _keepFactory.openKeep.value(msg.value)(_n, _m, msg.sender, _bond, _maxSecuredLifetime);
uint256 bond = calculateBondRequirementWei(_lotSizeSatoshis);
return _keepFactory.openKeep.value(msg.value)(keepSize, keepThreshold, msg.sender, bond, _maxSecuredLifetime);
}

/// @notice Check if a lot size is allowed.
/// @param _lotSizeSatoshis Lot size to check.
/// @return True if lot size is allowed, false otherwise.
function isAllowedLotSize(uint64 _lotSizeSatoshis) public view returns (bool){
for( uint i = 0; i < lotSizesSatoshis.length; i++){
if (lotSizesSatoshis[i] == _lotSizeSatoshis){
return true;
}
}
return false;
}

/// @notice Calculates bond requirement in wei for the given lot size in
/// satoshis based on the current ETHBTC price.
Copy link
Contributor

Choose a reason for hiding this comment

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

🐗

/// @param _lotSizeSatoshis Lot size in satoshis.
/// @return Bond requirement in wei.
function calculateBondRequirementWei(
uint256 _lotSizeSatoshis
) internal view returns (uint256) {
uint256 bondRequirementSatoshis = _lotSizeSatoshis.mul(
initialCollateralizedPercent
).div(100);
return _fetchBitcoinPrice().mul(bondRequirementSatoshis);
}

function _fetchBitcoinPrice() internal view returns (uint256) {
uint256 price = priceFeed.getPrice();
if (price == 0 || price > 10 ** 18) {
// This is if a sat is worth 0 wei, or is worth >1 ether. Revert at
// once.
revert("System returned a bad price");
}
return price;
}

/// @notice Get the time remaining until the function parameter timer value can be updated.
Expand Down
4 changes: 1 addition & 3 deletions solidity/contracts/test/deposit/TestDeposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ contract TestDeposit is Deposit {
IERC721 _tbtcDepositToken,
FeeRebateToken _feeRebateToken,
address _vendingMachineAddress,
uint16 _m,
uint16 _n,
uint64 _lotSizeSatoshis
) public payable {
self.tbtcSystem = _tbtcSystem;
self.tbtcToken = _tbtcToken;
self.tbtcDepositToken = _tbtcDepositToken;
self.feeRebateToken = _feeRebateToken;
self.vendingMachineAddress = _vendingMachineAddress;
self.initialize(_m, _n, _lotSizeSatoshis);
self.initialize(_lotSizeSatoshis);
}

function setExteriorAddresses(
Expand Down
Loading