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

Commit a1c696a

Browse files
authored
Merge pull request #424 from keep-network/emergency-pause-new-deposit
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.
2 parents 2e20ea8 + 642e81c commit a1c696a

File tree

5 files changed

+143
-29
lines changed

5 files changed

+143
-29
lines changed

implementation/contracts/system/TBTCSystem.sol

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@ import {IBTCETHPriceFeed} from "../interfaces/IBTCETHPriceFeed.sol";
99
import {DepositLog} from "../DepositLog.sol";
1010

1111
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
12+
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
1213

1314
contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
1415

15-
event LogLotSizesUpdated(uint256[] _lotSizes);
16-
event LogAllowNewDepositsUpdated(bool _allowNewDeposits);
17-
event LogSignerFeeDivisorUpdated(uint256 _signerFeeDivisor);
18-
event LogCollateralizationThresholdsUpdated(
16+
using SafeMath for uint256;
17+
18+
event LotSizesUpdated(uint256[] _lotSizes);
19+
event AllowNewDepositsUpdated(bool _allowNewDeposits);
20+
event SignerFeeDivisorUpdated(uint256 _signerFeeDivisor);
21+
event CollateralizationThresholdsUpdated(
1922
uint256 _undercollateralizedThresholdPercent,
2023
uint256 _severelyUndercollateralizedThresholdPercent
2124
);
2225

2326
bool _initialized = false;
27+
uint256 pausedTimestamp;
28+
uint256 pausedDuration = 10 days;
2429

2530
uint256 currentDifficulty = 1;
2631
uint256 previousDifficulty = 1;
@@ -29,7 +34,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
2934
address public priceFeed;
3035

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

4752
keepRegistry = _keepRegistry;
4853
_initialized = true;
54+
allowNewDeposits = true;
4955
}
5056

51-
/// @notice Enables/disables new deposits from being created.
52-
/// @param _allowNewDeposits Whether to allow new deposits.
53-
function setAllowNewDeposits(bool _allowNewDeposits)
54-
external onlyOwner
55-
{
56-
allowNewDeposits = _allowNewDeposits;
57-
emit LogAllowNewDepositsUpdated(_allowNewDeposits);
57+
/// @notice gets whether new deposits are allowed
58+
function getAllowNewDeposits() external view returns (bool) { return allowNewDeposits; }
59+
60+
/// @notice One-time-use emergency function to disallow future deposit creation for 10 days.
61+
function emergencyPauseNewDeposits() external onlyOwner returns (bool) {
62+
require(pausedTimestamp == 0, "emergencyPauseNewDeposits can only be called once");
63+
pausedTimestamp = block.timestamp;
64+
allowNewDeposits = false;
65+
emit AllowNewDepositsUpdated(false);
5866
}
5967

60-
/// @notice Gets whether new deposits are allowed.
61-
function getAllowNewDeposits() external view returns (bool) { return allowNewDeposits; }
68+
/// @notice Anyone can reactivate deposit creations after the pause duration is over.
69+
function resumeNewDeposits() public {
70+
require(allowNewDeposits == false, "New deposits are currently allowed");
71+
require(block.timestamp.sub(pausedTimestamp) >= pausedDuration, "Deposits are still paused");
72+
allowNewDeposits = true;
73+
emit AllowNewDepositsUpdated(true);
74+
}
75+
76+
function getRemainingPauseTerm() public view returns (uint256) {
77+
require(allowNewDeposits == false, "New deposits are currently allowed");
78+
return (block.timestamp.sub(pausedTimestamp) >= pausedDuration)?
79+
0:
80+
pausedDuration.sub(block.timestamp.sub(pausedTimestamp));
81+
}
6282

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

7393
/// @notice Gets the system signer fee divisor.
@@ -78,8 +98,14 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
7898
/// @dev Lot sizes should be
7999
/// @param _lotSizes Array of allowed lot sizes.
80100
function setLotSizes(uint256[] calldata _lotSizes) external onlyOwner {
81-
lotSizesSatoshis = _lotSizes;
82-
emit LogLotSizesUpdated(_lotSizes);
101+
for( uint i = 0; i < _lotSizes.length; i++){
102+
if (_lotSizes[i] == 10**8){
103+
lotSizesSatoshis = _lotSizes;
104+
emit LotSizesUpdated(_lotSizes);
105+
return;
106+
}
107+
}
108+
revert("Lot size array must always contain 1BTC");
83109
}
84110

85111
/// @notice Gets the allowed lot sizes
@@ -113,7 +139,7 @@ contract TBTCSystem is Ownable, ITBTCSystem, DepositLog {
113139
);
114140
undercollateralizedThresholdPercent = _undercollateralizedThresholdPercent;
115141
severelyUndercollateralizedThresholdPercent = _severelyUndercollateralizedThresholdPercent;
116-
emit LogCollateralizationThresholdsUpdated(
142+
emit CollateralizationThresholdsUpdated(
117143
_undercollateralizedThresholdPercent,
118144
_severelyUndercollateralizedThresholdPercent
119145
);

implementation/test/DepositFactoryTest.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ contract('DepositFactory', (accounts) => {
4545
factory = await DepositFactory.new(depositContract.address)
4646

4747
tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
48+
tbtcSystemStub.initialize(utils.address0)
4849

4950
tbtcToken = await TBTCToken.new(tbtcSystemStub.address)
5051
tbtcDepositToken = deployed.TBTCDepositToken

implementation/test/DepositFundingTest.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import expectThrow from './helpers/expectThrow'
2+
import {
3+
createSnapshot,
4+
restoreSnapshot,
5+
} from './helpers/snapshot'
26

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

9296
tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
97+
tbtcSystemStub.initialize(utils.address0)
9398

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

109114
beneficiary = accounts[4]
115+
await testInstance.reset()
116+
await testInstance.setKeepAddress(deployed.ECDSAKeepStub.address)
110117
})
111118

112119
beforeEach(async () => {
113-
await testInstance.reset()
114-
await testInstance.setKeepAddress(deployed.ECDSAKeepStub.address)
120+
await createSnapshot()
121+
})
122+
123+
afterEach(async () => {
124+
await restoreSnapshot()
115125
})
116126

117127
describe('createNewDeposit', async () => {
@@ -172,7 +182,7 @@ contract('DepositFunding', (accounts) => {
172182
})
173183

174184
it('fails if new deposits are disabled', async () => {
175-
await tbtcSystemStub.setAllowNewDeposits(false)
185+
await tbtcSystemStub.emergencyPauseNewDeposits()
176186

177187
await expectThrow(
178188
testInstance.createNewDeposit.call(
@@ -187,8 +197,6 @@ contract('DepositFunding', (accounts) => {
187197
),
188198
'Opening new deposits is currently disabled.'
189199
)
190-
191-
await tbtcSystemStub.setAllowNewDeposits(true)
192200
})
193201

194202
it.skip('stores payment value as funder\'s bond', async () => {

implementation/test/DepositUtilsTest.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ contract('DepositUtils', (accounts) => {
8585
deployed = await utils.deploySystem(TEST_DEPOSIT_UTILS_DEPLOY)
8686

8787
tbtcSystemStub = await TBTCSystemStub.new(utils.address0)
88+
tbtcSystemStub.initialize(utils.address0)
8889

8990
tbtcToken = await TestToken.new(tbtcSystemStub.address)
9091

implementation/test/TBTCSystemTest.js

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import expectThrow from './helpers/expectThrow'
2+
import increaseTime from './helpers/increaseTime'
3+
import {
4+
createSnapshot,
5+
restoreSnapshot,
6+
} from './helpers/snapshot'
27

38
const BN = require('bn.js')
49
const utils = require('./utils')
@@ -84,18 +89,91 @@ contract('TBTCSystem', (accounts) => {
8489
})
8590
})
8691

87-
describe('setAllowNewDeposits', async () => {
88-
it('sets allowNewDeposits', async () => {
89-
await tbtcSystem.setAllowNewDeposits(false)
92+
describe('setLotSizes', async () => {
93+
it('sets a different lot size array', async () => {
94+
const blockNumber = await web3.eth.getBlock('latest').number
95+
const lotSizes = [10**8, 10**6]
96+
await tbtcSystem.setLotSizes(lotSizes)
97+
98+
const eventList = await tbtcSystem.getPastEvents('LotSizesUpdated', { fromBlock: blockNumber, toBlock: 'latest' })
99+
assert.equal(eventList.length, 1)
100+
expect(eventList[0].returnValues._lotSizes).to.eql(['100000000', '1000000']) // deep equality check
101+
})
102+
103+
it('reverts if lot size array is empty', async () => {
104+
const lotSizes = []
105+
await expectThrow(
106+
tbtcSystem.setLotSizes(lotSizes),
107+
'Lot size array must always contain 1BTC'
108+
)
109+
})
110+
111+
it('reverts if lot size array does not contain a 1BTC lot size', async () => {
112+
const lotSizes = [10**7]
113+
await expectThrow(
114+
tbtcSystem.setLotSizes(lotSizes),
115+
'Lot size array must always contain 1BTC'
116+
)
117+
})
118+
})
119+
120+
describe('emergencyPauseNewDeposits', async () => {
121+
let term
122+
123+
beforeEach(async () => {
124+
await createSnapshot()
125+
})
126+
127+
afterEach(async () => {
128+
await restoreSnapshot()
129+
})
130+
131+
it('pauses new deposit creation', async () => {
132+
await tbtcSystem.emergencyPauseNewDeposits()
90133

91134
const allowNewDeposits = await tbtcSystem.getAllowNewDeposits()
92135
expect(allowNewDeposits).to.equal(false)
93136
})
94137

95-
it('reverts if msg.sender != owner', async () => {
138+
it('reverts if msg.sender is not owner', async () => {
96139
await expectThrow(
97-
tbtcSystem.setAllowNewDeposits(false, { from: accounts[1] }),
98-
''
140+
tbtcSystem.emergencyPauseNewDeposits({ from: accounts[1] }),
141+
'Ownable: caller is not the owner'
142+
)
143+
})
144+
145+
it('does not allows new deposit re-activation before 10 days', async () => {
146+
await tbtcSystem.emergencyPauseNewDeposits()
147+
term = await tbtcSystem.getRemainingPauseTerm()
148+
149+
await increaseTime(term.toNumber() - 10) // T-10 seconds. toNumber because increaseTime doesn't support BN
150+
151+
await expectThrow(
152+
tbtcSystem.resumeNewDeposits(),
153+
'Deposits are still paused'
154+
)
155+
})
156+
157+
it('allows new deposit creation after 10 days', async () => {
158+
await tbtcSystem.emergencyPauseNewDeposits()
159+
term = await tbtcSystem.getRemainingPauseTerm()
160+
161+
await increaseTime(term.toNumber()) // 10 days
162+
tbtcSystem.resumeNewDeposits()
163+
const allowNewDeposits = await tbtcSystem.getAllowNewDeposits()
164+
expect(allowNewDeposits).to.equal(true)
165+
})
166+
167+
it('reverts if emergencyPauseNewDeposits has already been called', async () => {
168+
await tbtcSystem.emergencyPauseNewDeposits()
169+
term = await tbtcSystem.getRemainingPauseTerm()
170+
171+
await increaseTime(term.toNumber()) // 10 days
172+
tbtcSystem.resumeNewDeposits()
173+
174+
await expectThrow(
175+
tbtcSystem.emergencyPauseNewDeposits(),
176+
'emergencyPauseNewDeposits can only be called once'
99177
)
100178
})
101179
})

0 commit comments

Comments
 (0)