Skip to content
Open

Sla #80

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
105 changes: 64 additions & 41 deletions contract/bridge/contracts/ExchangeRateOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,45 @@ https://onebtc-dev.web.app/spec/oracle.html
The Exchange Rate Oracle receives a continuous data feed on the exchange rate between BTC and ONE.
*/

pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/math/MathUpgradeable.sol";

contract ExchangeRateOracle is Initializable {
using SafeMathUpgradeable for uint256;
pragma solidity ^0.6.12;

contract ExchangeRateOracle {
uint256 constant MAX_DELAY = 1000;

uint256 public lastExchangeRateTime;
uint256 exchangeRate;

mapping(address => bool) authorizedOracles;

event SetExchangeRate(address oracle, uint256 rate);

event recoverFromORACLEOFFLINE(address oracle, uint256 rate);

function initialize(address provider) public initializer {
lastExchangeRateTime = now;
authorizedOracles[provider] = true;
uint256 satoshiPerBytes;
mapping (address => bool) authorizedOracles;

event SetExchangeRate(
address oracle,
uint256 rate
);

event SetSatoshiPerByte(
uint256 fee,
uint256 inclusionEstimate
);

event recoverFromORACLEOFFLINE(
address oracle,
uint256 rate
);

constructor() public {
authorizedOracles[0x5B38Da6a701c568545dCfcB03FcB875f56beddC4] = true;
}

function setExchangeRate(uint256 btcPrice, uint256 onePrice) public {
address oracle = msg.sender;
require(authorizedOracles[oracle], "Sender is not authorized");
/**
@notice Set the latest (aggregate) BTC/ONE exchange rate. This function invokes a check of vault collateral rates in the Vault Registry component.
@param oracle the oracle account calling this function. Must be pre-authorized and tracked in this component!
@param rate the u128 BTC/ONE exchange rate.
*/
function setExchangeRate(address oracle, uint256 rate) public {
require(authorizedOracles[oracle], "ERR_INVALID_ORACLE_SOURCE");

uint256 rate = btcPrice.div(onePrice);
exchangeRate = rate;

if (now - lastExchangeRateTime > MAX_DELAY) {
if (lastExchangeRateTime - now > MAX_DELAY) {
emit recoverFromORACLEOFFLINE(oracle, rate);
}

Expand All @@ -48,32 +54,49 @@ contract ExchangeRateOracle is Initializable {
emit SetExchangeRate(oracle, rate);
}

function getExchangeRate() private view returns (uint256) {
require(
now - lastExchangeRateTime <= MAX_DELAY,
"Exchange rate avaialble is too old"
);
/**
@notice Set the Satoshi per bytes fee
@param fee the Satoshi per byte fee.
@param inclusionEstimate the estimated inclusion time.
*/
function setSatoshiPerBytes(uint256 fee, uint256 inclusionEstimate) public {
// 1. The BTC Bridge status in the Security component MUST be set to RUNNING:0.
// TODO require()

require(authorizedOracles[msg.sender], "ERR_INVALID_ORACLE_SOURCE");

satoshiPerBytes = inclusionEstimate;

emit SetSatoshiPerByte(fee, inclusionEstimate);
}

/**
@notice Returns the latest BTC/ONE exchange rate, as received from the external data sources.
@return uint256 (aggregate) exchange rate value
*/
function getExchangeRate() public view returns (uint256) {
require (now - lastExchangeRateTime > MAX_DELAY, "ERR_MISSING_EXCHANGE_RATE");

return exchangeRate;
}

/**
* @notice Get BTC amount by ONE.
* @param amount collateral(ONE) amount
* @return BTC amount
*/
function collateralToWrapped(uint256 amount) public view returns (uint256) {
* @notice Get BTC amount by ONE.
* @param amount collateral(ONE) amount
* @return BTC amount
*/
function collateralToWrapped(uint256 amount) public view returns(uint256) {
uint256 rate = getExchangeRate();
return amount.div(rate).mul(10**8).div(10**18);
return amount/rate;
}

/**
* @notice Get ONE amount by BTC.
* @param amount BTC amount
* @return ONE amount
*/
function wrappedToCollateral(uint256 amount) public view returns (uint256) {
* @notice Get ONE amount by BTC.
* @param amount BTC amount
* @return ONE amount
*/
function wrappedToCollateral(uint256 amount) public view returns(uint256) {
uint256 rate = getExchangeRate();
return amount.mul(rate).mul(10**18).div(10**8);
return amount*rate;
}
}
150 changes: 137 additions & 13 deletions contract/bridge/contracts/SLA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

pragma solidity 0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";

contract SLA {

using SafeMath for uint256;

event UpdateVaultSLA(
address indexed vaultId,
uint256 boundedNewSla,
Expand All @@ -12,7 +17,7 @@ contract SLA {
event UpdateRelayerSLA(
address indexed relayerId,
uint256 newSla,
uint256 deltaSla
int256 deltaSla
);

enum VaultEvent {
Expand Down Expand Up @@ -44,16 +49,46 @@ contract SLA {
uint256 withdraw;
uint256 liquidate;
uint256 sla;
uint256 vaultTargetSla;
}

uint256 public VaultSLATarget = 100;
int256 public FailedRedeem = -100;

mapping(address => SlaData) VaultSLA;
mapping(address => SlaData) StakedRelayerSLA;
mapping(address => bool) VaultTrue;


/*
- adjust stake
- liquidate stake
- calculate slashed amount
- fixed point unsigned to signed
- wrapper to uint128
- currency to fixed point
*/

constructor( uint256 _TotalIssueCount,
uint256 _LifetimeIssued,
uint256 _VaultExecuteIssueMaxSlaChange,
uint256 _VaultDepositMaxSlaChange,
uint256 _VaultWithdrawMaxSlaChange,
uint256 _AverageDepositCount,
uint256 _AverageDeposit,
uint256 _AverageWithdrawCount,
uint256 _AverageWithdraw) public {
TotalIssueCount = _TotalIssueCount;
LifetimeIssued = _LifetimeIssued;
VaultDepositMaxSlaChange = _VaultDepositMaxSlaChange;
VaultWithdrawMaxSlaChange = _VaultWithdrawMaxSlaChange;
AverageDeposit = _AverageDeposit;
AverageDepositCount = _AverageDepositCount;
AverageWithdraw = _AverageWithdraw;
AverageWithdrawCount = _AverageWithdrawCount;
}

function _executeIssueSlaChange(uint256 amount) private returns (uint256) {

function _executeIssueSlaChange(uint256 amount) internal returns (uint256) {
uint256 count = TotalIssueCount + 1;
TotalIssueCount = count;
uint256 total = LifetimeIssued + amount;
Expand All @@ -64,7 +99,12 @@ contract SLA {
return (amount * maxSlaChange) / average;
}

function _depositSlaChange(uint256 amount) private returns (uint256) {

// Calculates the potential sla change for a vault depositing collateral. The value will be
// clipped between 0 and VaultDepositMaxSlaChange, but it does not take into consideration
// Vault's current SLA. It can return a value > 0 when its sla is already at the maximum.

function _depositSlaChange(uint256 amount) internal returns (uint256) {
uint256 maxSlaChange = VaultDepositMaxSlaChange;

uint256 count = AverageDepositCount + 1;
Expand All @@ -76,7 +116,7 @@ contract SLA {
return (amount / average) * maxSlaChange;
}

function _withdrawSlaChange(uint256 amount) private returns (uint256) {
function _withdrawSlaChange(uint256 amount) internal returns (uint256) {
uint256 maxSlaChange = VaultWithdrawMaxSlaChange;

uint256 count = AverageWithdrawCount + 1;
Expand All @@ -88,11 +128,11 @@ contract SLA {
return (amount / average) * maxSlaChange;
}

function _liquidateSla(address vaultId) private returns (int256) {
function _liquidateSla(address vaultId) internal returns (int256) {
// TODO
//Self::liquidateStake::<T::CollateralVaultRewards>(vaultId)?;
//Self::liquidateStake::<T::WrappedVaultRewards>(vaultId)?;
revert("TODO");
// revert("TODO");
SlaData storage slaData = VaultSLA[vaultId];
int256 deltaSla = -int256(slaData.sla);
slaData.sla = 0;
Expand All @@ -103,11 +143,13 @@ contract SLA {
uint256 min,
uint256 cur,
uint256 max
) private pure returns (uint256) {
) internal pure returns (uint256) {
return cur > max ? max : (cur > min ? cur : min);
}

function eventUpdateVaultSla(
event data (uint256,uint256,uint256, uint256);

function _eventUpdateVaultSla(
address vaultId,
VaultEvent eventType,
uint256 amount
Expand All @@ -131,11 +173,11 @@ contract SLA {
_liquidateSla(vaultId);
return;
} else {
revert("unknow type");
revert("unknown type");
}

uint256 newSla = currentSla + deltaSla;
uint256 maxSla = slaData.vaultTargetSla; // todo: check that this is indeed the max
uint256 maxSla = VaultSLATarget; // todo: check that this is indeed the max

uint256 boundedNewSla = limit(0, newSla, maxSla);
/*
Expand All @@ -146,7 +188,89 @@ contract SLA {
emit UpdateVaultSLA(vaultId, boundedNewSla, int256(deltaSla));
}

function SlashVault(address account) internal returns (uint256) {}

function updateSLA(address account, uint256 delta) internal {}
function _eventUpdateRelayerSla(
address relayerId,
VaultEvent eventType,
uint256 amount
) internal {
SlaData storage slaData = StakedRelayerSLA[relayerId];
uint256 currentSla = slaData.sla;
uint256 deltaSla;
if (eventType == VaultEvent.RedeemFailure) {
deltaSla = slaData.vaultRedeemFailure;
} else if (eventType == VaultEvent.SubmitIssueProof) {
deltaSla = slaData.vaultSubmitIssueProof;
} else if (eventType == VaultEvent.Refund) {
deltaSla = slaData.vaultRefund;
} else if (eventType == VaultEvent.ExecuteIssue) {
deltaSla = _executeIssueSlaChange(amount);
} else if (eventType == VaultEvent.Deposit) {
deltaSla = _depositSlaChange(amount);
} else if (eventType == VaultEvent.Withdraw) {
deltaSla = _withdrawSlaChange(amount);
} else if (eventType == VaultEvent.Liquidate) {
_liquidateSla(relayerId);
return;
} else {
revert("unknown type");
}

uint256 newSla = currentSla + deltaSla;
uint256 maxSla = VaultSLATarget; // todo: check that this is indeed the max

uint256 boundedNewSla = limit(0, newSla, maxSla);
/*
Self::adjustStake::<T::CollateralVaultRewards>(vaultId, deltaSla)?;
Self::adjustStake::<T::WrappedVaultRewards>(vaultId, deltaSla)?;
*/
slaData.sla = boundedNewSla;
emit UpdateVaultSLA(relayerId, boundedNewSla, int256(deltaSla));
}

function calculateSlashAmount(address account) internal returns (uint256) {
SlaData memory vault = VaultSLA[account];
uint256 slaTarget = VaultSLATarget;
uint256 sla = vault.sla;
uint256 liquidateThreshold = vault.liquidate;
uint256 premiumRedeemThreshold = vault.vaultRedeemFailure;

uint256 realSlashed = premiumRedeemThreshold.sub(liquidateThreshold).div(slaTarget).mul(sla).add(liquidateThreshold);

return realSlashed;
}

function updateVaultSLA(address account, int256 delta) internal {
SlaData storage vault;
vault = VaultSLA[account];

if(delta > 0){
vault.sla = vault.sla + uint256(delta);
}
if(delta <0){
vault.sla = vault.sla - uint256(delta);
}
UpdateVaultSLA(account, vault.sla, delta);
}

function _updateRelayerSla(address account, int256 delta) internal {
SlaData storage vault = StakedRelayerSLA[account];
if(delta > 0){
vault.sla = vault.sla + uint256(delta);
}
if(delta <0){
vault.sla = vault.sla - uint256(delta);
}
UpdateRelayerSLA(account, vault.sla, delta);

}


function getRelayerSla ( address vaultId) public view returns (uint256){
return StakedRelayerSLA[vaultId].sla;
}

function getVaultSla(address vaultId) public view returns (uint256 ){
return VaultSLA[vaultId].sla;
}
}
Loading