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

Commit

Permalink
Merge pull request #424 from keep-network/emergency-pause-new-deposit
Browse files Browse the repository at this point in the history
Emergency pause new deposit

- Add a one-time function that pauses deposit creation for 10 days.
- Lot size updates no longer allow the removal of the 1 BTC lot size.
  • Loading branch information
Shadowfiend authored Feb 1, 2020
2 parents 2e20ea8 + 642e81c commit a1c696a
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 29 deletions.
62 changes: 44 additions & 18 deletions implementation/contracts/system/TBTCSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ import {IBTCETHPriceFeed} from "../interfaces/IBTCETHPriceFeed.sol";
import {DepositLog} from "../DepositLog.sol";

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";

contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {

event LogLotSizesUpdated(uint256[] _lotSizes);
event LogAllowNewDepositsUpdated(bool _allowNewDeposits);
event LogSignerFeeDivisorUpdated(uint256 _signerFeeDivisor);
event LogCollateralizationThresholdsUpdated(
using SafeMath for uint256;

event LotSizesUpdated(uint256[] _lotSizes);
event AllowNewDepositsUpdated(bool _allowNewDeposits);
event SignerFeeDivisorUpdated(uint256 _signerFeeDivisor);
event CollateralizationThresholdsUpdated(
uint256 _undercollateralizedThresholdPercent,
uint256 _severelyUndercollateralizedThresholdPercent
);

bool _initialized = false;
uint256 pausedTimestamp;
uint256 pausedDuration = 10 days;

uint256 currentDifficulty = 1;
uint256 previousDifficulty = 1;
Expand All @@ -29,7 +34,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
address public priceFeed;

// Parameters governed by the TBTCSystem owner
bool private allowNewDeposits = true;
bool private allowNewDeposits = false;
uint256 private signerFeeDivisor = 200; // 1/200 == 50bps == 0.5% == 0.005
uint128 private undercollateralizedThresholdPercent = 140; // percent
uint128 private severelyUndercollateralizedThresholdPercent = 120; // percent
Expand All @@ -46,19 +51,34 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {

keepRegistry = _keepRegistry;
_initialized = true;
allowNewDeposits = true;
}

/// @notice Enables/disables new deposits from being created.
/// @param _allowNewDeposits Whether to allow new deposits.
function setAllowNewDeposits(bool _allowNewDeposits)
external onlyOwner
{
allowNewDeposits = _allowNewDeposits;
emit LogAllowNewDepositsUpdated(_allowNewDeposits);
/// @notice gets whether new deposits are allowed
function getAllowNewDeposits() external view returns (bool) { return allowNewDeposits; }

/// @notice One-time-use emergency function to disallow future deposit creation for 10 days.
function emergencyPauseNewDeposits() external onlyOwner returns (bool) {
require(pausedTimestamp == 0, "emergencyPauseNewDeposits can only be called once");
pausedTimestamp = block.timestamp;
allowNewDeposits = false;
emit AllowNewDepositsUpdated(false);
}

/// @notice Gets whether new deposits are allowed.
function getAllowNewDeposits() external view returns (bool) { return allowNewDeposits; }
/// @notice Anyone can reactivate deposit creations after the pause duration is over.
function resumeNewDeposits() public {
require(allowNewDeposits == false, "New deposits are currently allowed");
require(block.timestamp.sub(pausedTimestamp) >= pausedDuration, "Deposits are still paused");
allowNewDeposits = true;
emit AllowNewDepositsUpdated(true);
}

function getRemainingPauseTerm() public view returns (uint256) {
require(allowNewDeposits == false, "New deposits are currently allowed");
return (block.timestamp.sub(pausedTimestamp) >= pausedDuration)?
0:
pausedDuration.sub(block.timestamp.sub(pausedTimestamp));
}

/// @notice Set the system signer fee divisor.
/// @param _signerFeeDivisor The signer fee divisor.
Expand All @@ -67,7 +87,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
{
require(_signerFeeDivisor > 1, "Signer fee must be lower than 100%");
signerFeeDivisor = _signerFeeDivisor;
emit LogSignerFeeDivisorUpdated(_signerFeeDivisor);
emit SignerFeeDivisorUpdated(_signerFeeDivisor);
}

/// @notice Gets the system signer fee divisor.
Expand All @@ -78,8 +98,14 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
/// @dev Lot sizes should be
/// @param _lotSizes Array of allowed lot sizes.
function setLotSizes(uint256[] calldata _lotSizes) external onlyOwner {
lotSizesSatoshis = _lotSizes;
emit LogLotSizesUpdated(_lotSizes);
for( uint i = 0; i < _lotSizes.length; i++){
if (_lotSizes[i] == 10**8){
lotSizesSatoshis = _lotSizes;
emit LotSizesUpdated(_lotSizes);
return;
}
}
revert("Lot size array must always contain 1BTC");
}

/// @notice Gets the allowed lot sizes
Expand Down Expand Up @@ -113,7 +139,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
);
undercollateralizedThresholdPercent = _undercollateralizedThresholdPercent;
severelyUndercollateralizedThresholdPercent = _severelyUndercollateralizedThresholdPercent;
emit LogCollateralizationThresholdsUpdated(
emit CollateralizationThresholdsUpdated(
_undercollateralizedThresholdPercent,
_severelyUndercollateralizedThresholdPercent
);
Expand Down
1 change: 1 addition & 0 deletions implementation/test/DepositFactoryTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ contract('DepositFactory', (accounts) => {
factory = await DepositFactory.new(depositContract.address)

tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
tbtcSystemStub.initialize(utils.address0)

tbtcToken = await TBTCToken.new(tbtcSystemStub.address)
tbtcDepositToken = deployed.TBTCDepositToken
Expand Down
18 changes: 13 additions & 5 deletions implementation/test/DepositFundingTest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import expectThrow from './helpers/expectThrow'
import {
createSnapshot,
restoreSnapshot,
} from './helpers/snapshot'

const BytesLib = artifacts.require('BytesLib')
const BTCUtils = artifacts.require('BTCUtils')
Expand Down Expand Up @@ -90,6 +94,7 @@ contract('DepositFunding', (accounts) => {
deployed = await utils.deploySystem(TEST_DEPOSIT_DEPLOY)

tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
tbtcSystemStub.initialize(utils.address0)

tbtcToken = await TestToken.new(tbtcSystemStub.address)
tbtcDepositToken = deployed.TBTCDepositToken
Expand All @@ -107,11 +112,16 @@ contract('DepositFunding', (accounts) => {
await tbtcDepositToken.forceMint(accounts[4], web3.utils.toBN(deployed.TestDeposit.address))

beneficiary = accounts[4]
await testInstance.reset()
await testInstance.setKeepAddress(deployed.ECDSAKeepStub.address)
})

beforeEach(async () => {
await testInstance.reset()
await testInstance.setKeepAddress(deployed.ECDSAKeepStub.address)
await createSnapshot()
})

afterEach(async () => {
await restoreSnapshot()
})

describe('createNewDeposit', async () => {
Expand Down Expand Up @@ -172,7 +182,7 @@ contract('DepositFunding', (accounts) => {
})

it('fails if new deposits are disabled', async () => {
await tbtcSystemStub.setAllowNewDeposits(false)
await tbtcSystemStub.emergencyPauseNewDeposits()

await expectThrow(
testInstance.createNewDeposit.call(
Expand All @@ -187,8 +197,6 @@ contract('DepositFunding', (accounts) => {
),
'Opening new deposits is currently disabled.'
)

await tbtcSystemStub.setAllowNewDeposits(true)
})

it.skip('stores payment value as funder\'s bond', async () => {
Expand Down
1 change: 1 addition & 0 deletions implementation/test/DepositUtilsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ contract('DepositUtils', (accounts) => {
deployed = await utils.deploySystem(TEST_DEPOSIT_UTILS_DEPLOY)

tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
tbtcSystemStub.initialize(utils.address0)

tbtcToken = await TestToken.new(tbtcSystemStub.address)

Expand Down
90 changes: 84 additions & 6 deletions implementation/test/TBTCSystemTest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import expectThrow from './helpers/expectThrow'
import increaseTime from './helpers/increaseTime'
import {
createSnapshot,
restoreSnapshot,
} from './helpers/snapshot'

const BN = require('bn.js')
const utils = require('./utils')
Expand Down Expand Up @@ -84,18 +89,91 @@ contract('TBTCSystem', (accounts) => {
})
})

describe('setAllowNewDeposits', async () => {
it('sets allowNewDeposits', async () => {
await tbtcSystem.setAllowNewDeposits(false)
describe('setLotSizes', async () => {
it('sets a different lot size array', async () => {
const blockNumber = await web3.eth.getBlock('latest').number
const lotSizes = [10**8, 10**6]
await tbtcSystem.setLotSizes(lotSizes)

const eventList = await tbtcSystem.getPastEvents('LotSizesUpdated', { fromBlock: blockNumber, toBlock: 'latest' })
assert.equal(eventList.length, 1)
expect(eventList[0].returnValues._lotSizes).to.eql(['100000000', '1000000']) // deep equality check
})

it('reverts if lot size array is empty', async () => {
const lotSizes = []
await expectThrow(
tbtcSystem.setLotSizes(lotSizes),
'Lot size array must always contain 1BTC'
)
})

it('reverts if lot size array does not contain a 1BTC lot size', async () => {
const lotSizes = [10**7]
await expectThrow(
tbtcSystem.setLotSizes(lotSizes),
'Lot size array must always contain 1BTC'
)
})
})

describe('emergencyPauseNewDeposits', async () => {
let term

beforeEach(async () => {
await createSnapshot()
})

afterEach(async () => {
await restoreSnapshot()
})

it('pauses new deposit creation', async () => {
await tbtcSystem.emergencyPauseNewDeposits()

const allowNewDeposits = await tbtcSystem.getAllowNewDeposits()
expect(allowNewDeposits).to.equal(false)
})

it('reverts if msg.sender != owner', async () => {
it('reverts if msg.sender is not owner', async () => {
await expectThrow(
tbtcSystem.setAllowNewDeposits(false, { from: accounts[1] }),
''
tbtcSystem.emergencyPauseNewDeposits({ from: accounts[1] }),
'Ownable: caller is not the owner'
)
})

it('does not allows new deposit re-activation before 10 days', async () => {
await tbtcSystem.emergencyPauseNewDeposits()
term = await tbtcSystem.getRemainingPauseTerm()

await increaseTime(term.toNumber() - 10) // T-10 seconds. toNumber because increaseTime doesn't support BN

await expectThrow(
tbtcSystem.resumeNewDeposits(),
'Deposits are still paused'
)
})

it('allows new deposit creation after 10 days', async () => {
await tbtcSystem.emergencyPauseNewDeposits()
term = await tbtcSystem.getRemainingPauseTerm()

await increaseTime(term.toNumber()) // 10 days
tbtcSystem.resumeNewDeposits()
const allowNewDeposits = await tbtcSystem.getAllowNewDeposits()
expect(allowNewDeposits).to.equal(true)
})

it('reverts if emergencyPauseNewDeposits has already been called', async () => {
await tbtcSystem.emergencyPauseNewDeposits()
term = await tbtcSystem.getRemainingPauseTerm()

await increaseTime(term.toNumber()) // 10 days
tbtcSystem.resumeNewDeposits()

await expectThrow(
tbtcSystem.emergencyPauseNewDeposits(),
'emergencyPauseNewDeposits can only be called once'
)
})
})
Expand Down

0 comments on commit a1c696a

Please sign in to comment.