Commit f24339f9 authored by Georgios Konstantopoulos's avatar Georgios Konstantopoulos Committed by GitHub

Bond Manager Deposit bugfix (#64)

* fix(bond): always deposit requiredCollateral

This means that we have to remove the setRequiredCollateral function to avoid:
1. Publisher deposits, requiredCollateral goes up, publisher withdraws more than they deposited
2. Publisher deposits, fraud happens, requiredCollateral goes up, more than the user's deposit gets
distributed in fraud claims

* fix(bond): remove redundant batchIndex parameter
parent 540149e1
...@@ -21,13 +21,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -21,13 +21,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
uint256 public constant disputePeriodSeconds = 7 days; uint256 public constant disputePeriodSeconds = 7 days;
/// The minimum collateral a sequencer must post /// The minimum collateral a sequencer must post
uint256 public requiredCollateral = 1 ether; uint256 public constant requiredCollateral = 1 ether;
/// The maximum multiplier for updating the `requiredCollateral`
uint256 public constant MAX = 5;
/// Owner used to bump the security bond size
address immutable public owner;
/******************************************* /*******************************************
...@@ -37,9 +31,6 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -37,9 +31,6 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
/// The bond token /// The bond token
ERC20 immutable public token; ERC20 immutable public token;
/// The fraud verifier contract, used to get data about transitioners for a pre-state root
address public ovmFraudVerifier;
/******************************************** /********************************************
* Contract Variables: Internal Accounting * * Contract Variables: Internal Accounting *
...@@ -62,7 +53,6 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -62,7 +53,6 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
constructor(ERC20 _token, address _libAddressManager) constructor(ERC20 _token, address _libAddressManager)
Lib_AddressResolver(_libAddressManager) Lib_AddressResolver(_libAddressManager)
{ {
owner = msg.sender;
token = _token; token = _token;
} }
...@@ -83,7 +73,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -83,7 +73,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
/// Slashes + distributes rewards or frees up the sequencer's bond, only called by /// Slashes + distributes rewards or frees up the sequencer's bond, only called by
/// `FraudVerifier.finalizeFraudVerification` /// `FraudVerifier.finalizeFraudVerification`
function finalize(bytes32 _preStateRoot, uint256 batchIndex, address publisher, uint256 timestamp) override public { function finalize(bytes32 _preStateRoot, address publisher, uint256 timestamp) override public {
require(msg.sender == resolve("OVM_FraudVerifier"), Errors.ONLY_FRAUD_VERIFIER); require(msg.sender == resolve("OVM_FraudVerifier"), Errors.ONLY_FRAUD_VERIFIER);
require(witnessProviders[_preStateRoot].canClaim == false, Errors.ALREADY_FINALIZED); require(witnessProviders[_preStateRoot].canClaim == false, Errors.ALREADY_FINALIZED);
...@@ -113,9 +103,9 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -113,9 +103,9 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
/// Sequencers call this function to post collateral which will be used for /// Sequencers call this function to post collateral which will be used for
/// the `appendBatch` call /// the `appendBatch` call
function deposit(uint256 amount) override public { function deposit() override public {
require( require(
token.transferFrom(msg.sender, address(this), amount), token.transferFrom(msg.sender, address(this), requiredCollateral),
Errors.ERC20_ERR Errors.ERC20_ERR
); );
...@@ -171,16 +161,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver { ...@@ -171,16 +161,7 @@ contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
require(token.transfer(msg.sender, amount), Errors.ERC20_ERR); require(token.transfer(msg.sender, amount), Errors.ERC20_ERR);
} }
/// Sets the required collateral for posting a state root /// Checks if the user is collateralized
/// Callable only by the contract's deployer.
function setRequiredCollateral(uint256 newValue) override public {
require(newValue > requiredCollateral, Errors.LOW_VALUE);
require(newValue < MAX * requiredCollateral, Errors.HIGH_VALUE);
require(msg.sender == owner, Errors.ONLY_OWNER);
requiredCollateral = newValue;
}
/// Checks if the user is collateralized for the batchIndex
function isCollateralized(address who) override public view returns (bool) { function isCollateralized(address who) override public view returns (bool) {
return bonds[who].state == State.COLLATERALIZED; return bonds[who].state == State.COLLATERALIZED;
} }
......
...@@ -203,7 +203,6 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr ...@@ -203,7 +203,6 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr
// slash the bonds at the bond manager // slash the bonds at the bond manager
ovmBondManager.finalize( ovmBondManager.finalize(
_preStateRoot, _preStateRoot,
_postStateRootBatchHeader.batchIndex,
publisher, publisher,
timestamp timestamp
); );
......
...@@ -9,8 +9,6 @@ interface ERC20 { ...@@ -9,8 +9,6 @@ interface ERC20 {
/// All the errors which may be encountered on the bond manager /// All the errors which may be encountered on the bond manager
library Errors { library Errors {
string constant ERC20_ERR = "BondManager: Could not post bond"; string constant ERC20_ERR = "BondManager: Could not post bond";
string constant LOW_VALUE = "BondManager: New collateral value must be greater than the previous one";
string constant HIGH_VALUE = "BondManager: New collateral value cannot be more than 5x of the previous one";
string constant ALREADY_FINALIZED = "BondManager: Fraud proof for this pre-state root has already been finalized"; string constant ALREADY_FINALIZED = "BondManager: Fraud proof for this pre-state root has already been finalized";
string constant SLASHED = "BondManager: Cannot finalize withdrawal, you probably got slashed"; string constant SLASHED = "BondManager: Cannot finalize withdrawal, you probably got slashed";
string constant WRONG_STATE = "BondManager: Wrong bond state for proposer"; string constant WRONG_STATE = "BondManager: Wrong bond state for proposer";
...@@ -19,7 +17,6 @@ library Errors { ...@@ -19,7 +17,6 @@ library Errors {
string constant WITHDRAWAL_PENDING = "BondManager: Withdrawal already pending"; string constant WITHDRAWAL_PENDING = "BondManager: Withdrawal already pending";
string constant TOO_EARLY = "BondManager: Too early to finalize your withdrawal"; string constant TOO_EARLY = "BondManager: Too early to finalize your withdrawal";
string constant ONLY_OWNER = "BondManager: Only the contract's owner can call this function";
string constant ONLY_TRANSITIONER = "BondManager: Only the transitioner for this pre-state root may call this function"; string constant ONLY_TRANSITIONER = "BondManager: Only the transitioner for this pre-state root may call this function";
string constant ONLY_FRAUD_VERIFIER = "BondManager: Only the fraud verifier may call this function"; string constant ONLY_FRAUD_VERIFIER = "BondManager: Only the fraud verifier may call this function";
string constant ONLY_STATE_COMMITMENT_CHAIN = "BondManager: Only the state commitment chain may call this function"; string constant ONLY_STATE_COMMITMENT_CHAIN = "BondManager: Only the state commitment chain may call this function";
...@@ -78,14 +75,11 @@ interface iOVM_BondManager { ...@@ -78,14 +75,11 @@ interface iOVM_BondManager {
function finalize( function finalize(
bytes32 _preStateRoot, bytes32 _preStateRoot,
uint256 _batchIndex,
address _publisher, address _publisher,
uint256 _timestamp uint256 _timestamp
) external; ) external;
function deposit( function deposit() external;
uint256 _amount
) external;
function startWithdrawal() external; function startWithdrawal() external;
...@@ -95,10 +89,6 @@ interface iOVM_BondManager { ...@@ -95,10 +89,6 @@ interface iOVM_BondManager {
bytes32 _preStateRoot bytes32 _preStateRoot
) external; ) external;
function setRequiredCollateral(
uint256 _newValue
) external;
function isCollateralized( function isCollateralized(
address _who address _who
) external view returns (bool); ) external view returns (bool);
......
...@@ -20,7 +20,7 @@ contract Mock_FraudVerifier { ...@@ -20,7 +20,7 @@ contract Mock_FraudVerifier {
return transitioners[preStateRoot]; return transitioners[preStateRoot];
} }
function finalize(bytes32 _preStateRoot, uint256 batchIndex, address publisher, uint256 timestamp) public { function finalize(bytes32 _preStateRoot, address publisher, uint256 timestamp) public {
bondManager.finalize(_preStateRoot, batchIndex, publisher, timestamp); bondManager.finalize(_preStateRoot, publisher, timestamp);
} }
} }
...@@ -71,39 +71,13 @@ describe('BondManager', () => { ...@@ -71,39 +71,13 @@ describe('BondManager', () => {
await fraudVerifier.setBondManager(bondManager.address) await fraudVerifier.setBondManager(bondManager.address)
}) })
describe('required collateral adjustment', () => {
it('bumps required collateral', async () => {
// sets collateral to 2 eth, which is more than what we have deposited
await bondManager.setRequiredCollateral(ethers.utils.parseEther('2'))
expect(await bondManager.isCollateralized(sender)).to.be.false
})
it('cannot lower collateral reqs', async () => {
await expect(
bondManager.setRequiredCollateral(ethers.utils.parseEther('0.99'))
).to.be.revertedWith(Errors.LOW_VALUE)
})
it('cannot increase collateral reqs to more than 5x of current value', async () => {
await expect(
bondManager.setRequiredCollateral(ethers.utils.parseEther('10.1'))
).to.be.revertedWith(Errors.HIGH_VALUE)
})
it('only owner can adjust collateral', async () => {
await expect(
bondManager.connect(wallets[2]).setRequiredCollateral(amount.add(1))
).to.be.revertedWith(Errors.ONLY_OWNER)
})
})
describe('collateral management', () => { describe('collateral management', () => {
let balanceBefore: BigNumber let balanceBefore: BigNumber
beforeEach(async () => { beforeEach(async () => {
await token.approve(bondManager.address, ethers.constants.MaxUint256) await token.approve(bondManager.address, ethers.constants.MaxUint256)
balanceBefore = await token.balanceOf(sender) balanceBefore = await token.balanceOf(sender)
await bondManager.deposit(amount) await bondManager.deposit()
}) })
it('can deposit', async () => { it('can deposit', async () => {
...@@ -207,7 +181,7 @@ describe('BondManager', () => { ...@@ -207,7 +181,7 @@ describe('BondManager', () => {
beforeEach(async () => { beforeEach(async () => {
// deposit the collateral to be distributed // deposit the collateral to be distributed
await token.approve(bondManager.address, ethers.constants.MaxUint256) await token.approve(bondManager.address, ethers.constants.MaxUint256)
await bondManager.deposit(amount) await bondManager.deposit()
// smodify the canClaim value to true to test claiming // smodify the canClaim value to true to test claiming
bondManager.smodify.set({ bondManager.smodify.set({
...@@ -256,28 +230,26 @@ describe('BondManager', () => { ...@@ -256,28 +230,26 @@ describe('BondManager', () => {
}) })
describe('finalize', () => { describe('finalize', () => {
const batchIdx = 1
beforeEach(async () => { beforeEach(async () => {
await token.approve(bondManager.address, ethers.constants.MaxUint256) await token.approve(bondManager.address, ethers.constants.MaxUint256)
await bondManager.deposit(amount) await bondManager.deposit()
}) })
it('only fraud verifier can finalize', async () => { it('only fraud verifier can finalize', async () => {
await expect( await expect(
bondManager.finalize(preStateRoot, batchIdx, sender, 0) bondManager.finalize(preStateRoot, sender, 0)
).to.be.revertedWith(Errors.ONLY_FRAUD_VERIFIER) ).to.be.revertedWith(Errors.ONLY_FRAUD_VERIFIER)
}) })
it('proving fraud allows claiming', async () => { it('proving fraud allows claiming', async () => {
await fraudVerifier.finalize(preStateRoot, batchIdx, sender, 0) await fraudVerifier.finalize(preStateRoot, sender, 0)
expect((await bondManager.witnessProviders(preStateRoot)).canClaim).to expect((await bondManager.witnessProviders(preStateRoot)).canClaim).to
.be.true .be.true
// cannot double finalize // cannot double finalize
await expect( await expect(
fraudVerifier.finalize(preStateRoot, batchIdx, sender, 0) fraudVerifier.finalize(preStateRoot, sender, 0)
).to.be.revertedWith(Errors.ALREADY_FINALIZED) ).to.be.revertedWith(Errors.ALREADY_FINALIZED)
}) })
...@@ -290,7 +262,6 @@ describe('BondManager', () => { ...@@ -290,7 +262,6 @@ describe('BondManager', () => {
const disputeTimestamp = withdrawalTimestamp - 100 const disputeTimestamp = withdrawalTimestamp - 100
await fraudVerifier.finalize( await fraudVerifier.finalize(
preStateRoot, preStateRoot,
batchIdx,
sender, sender,
disputeTimestamp disputeTimestamp
) )
...@@ -310,7 +281,6 @@ describe('BondManager', () => { ...@@ -310,7 +281,6 @@ describe('BondManager', () => {
const disputeTimestamp = withdrawalTimestamp - ONE_WEEK - 1 const disputeTimestamp = withdrawalTimestamp - ONE_WEEK - 1
await fraudVerifier.finalize( await fraudVerifier.finalize(
preStateRoot, preStateRoot,
batchIdx,
sender, sender,
disputeTimestamp disputeTimestamp
) )
...@@ -321,7 +291,7 @@ describe('BondManager', () => { ...@@ -321,7 +291,7 @@ describe('BondManager', () => {
}) })
it('proving fraud prevents starting a withdrawal due to slashing', async () => { it('proving fraud prevents starting a withdrawal due to slashing', async () => {
await fraudVerifier.finalize(preStateRoot, batchIdx, sender, 0) await fraudVerifier.finalize(preStateRoot, sender, 0)
await expect(bondManager.startWithdrawal()).to.be.revertedWith( await expect(bondManager.startWithdrawal()).to.be.revertedWith(
Errors.WRONG_STATE Errors.WRONG_STATE
) )
...@@ -342,8 +312,6 @@ enum State { ...@@ -342,8 +312,6 @@ enum State {
// Errors from the bond manager smart contract // Errors from the bond manager smart contract
enum Errors { enum Errors {
ERC20_ERR = 'BondManager: Could not post bond', ERC20_ERR = 'BondManager: Could not post bond',
LOW_VALUE = 'BondManager: New collateral value must be greater than the previous one',
HIGH_VALUE = 'BondManager: New collateral value cannot be more than 5x of the previous one',
ALREADY_FINALIZED = 'BondManager: Fraud proof for this pre-state root has already been finalized', ALREADY_FINALIZED = 'BondManager: Fraud proof for this pre-state root has already been finalized',
SLASHED = 'BondManager: Cannot finalize withdrawal, you probably got slashed', SLASHED = 'BondManager: Cannot finalize withdrawal, you probably got slashed',
WRONG_STATE = 'BondManager: Wrong bond state for proposer', WRONG_STATE = 'BondManager: Wrong bond state for proposer',
...@@ -352,7 +320,6 @@ enum Errors { ...@@ -352,7 +320,6 @@ enum Errors {
WITHDRAWAL_PENDING = 'BondManager: Withdrawal already pending', WITHDRAWAL_PENDING = 'BondManager: Withdrawal already pending',
TOO_EARLY = 'BondManager: Too early to finalize your withdrawal', TOO_EARLY = 'BondManager: Too early to finalize your withdrawal',
ONLY_OWNER = "BondManager: Only the contract's owner can call this function",
ONLY_TRANSITIONER = 'BondManager: Only the transitioner for this pre-state root may call this function', ONLY_TRANSITIONER = 'BondManager: Only the transitioner for this pre-state root may call this function',
ONLY_FRAUD_VERIFIER = 'BondManager: Only the fraud verifier may call this function', ONLY_FRAUD_VERIFIER = 'BondManager: Only the fraud verifier may call this function',
ONLY_STATE_COMMITMENT_CHAIN = 'BondManager: Only the state commitment chain may call this function', ONLY_STATE_COMMITMENT_CHAIN = 'BondManager: Only the state commitment chain may call this function',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment