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

Funding fraud refactor #534

Merged
merged 12 commits into from
Mar 27, 2020
43 changes: 0 additions & 43 deletions solidity/contracts/deposit/Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -302,49 +302,6 @@ contract Deposit is DepositFactoryAuthority {
return true;
}

/// @notice Anyone may notify the contract no funding proof was submitted during funding fraud.
/// @dev This is not a funder fault. The signers have faulted, so the funder shouldn't fund.
/// @return True if successful, otherwise revert.
function notifyFraudFundingTimeout() public returns (bool) {
self.notifyFraudFundingTimeout();
return true;
}

/// @notice Anyone may notify the deposit of a funding proof during funding fraud.
// We reward the funder the entire bond if this occurs.
/// @dev Takes a pre-parsed transaction and calculates values needed to verify funding.
/// @param _txVersion Transaction version number (4-byte LE).
/// @param _txInputVector All transaction inputs prepended by the number of inputs encoded as a VarInt, max 0xFC(252) inputs.
/// @param _txOutputVector All transaction outputs prepended by the number of outputs encoded as a VarInt, max 0xFC(252) outputs.
/// @param _txLocktime Final 4 bytes of the transaction.
/// @param _fundingOutputIndex Index of funding output in _txOutputVector (0-indexed).
/// @param _merkleProof The merkle proof of transaction inclusion in a block.
/// @param _txIndexInBlock Transaction index in the block (0-indexed).
/// @param _bitcoinHeaders Single bytestring of 80-byte bitcoin headers, lowest height first.
/// @return True if no errors are thrown.
function provideFraudBTCFundingProof(
bytes4 _txVersion,
bytes memory _txInputVector,
bytes memory _txOutputVector,
bytes4 _txLocktime,
uint8 _fundingOutputIndex,
bytes memory _merkleProof,
uint256 _txIndexInBlock,
bytes memory _bitcoinHeaders
) public returns (bool) {
self.provideFraudBTCFundingProof(
_txVersion,
_txInputVector,
_txOutputVector,
_txLocktime,
_fundingOutputIndex,
_merkleProof,
_txIndexInBlock,
_bitcoinHeaders
);
return true;
}

/// @notice Anyone may notify the deposit of a funding proof to activate the deposit.
/// This is the happy-path of the funding flow. It means that we have succeeded.
/// @dev Takes a pre-parsed transaction and calculates values needed to verify funding.
Expand Down
86 changes: 2 additions & 84 deletions solidity/contracts/deposit/DepositFunding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,6 @@ library DepositFunding {
return true;
}

/// @notice Slashes the signers partially for committing fraud before funding occurs.
/// @dev Called only by notifyFraudFundingTimeout.
function partiallySlashForFraudInFunding(DepositUtils.Deposit storage _d) internal {
uint256 _seized = _d.seizeSignerBonds();
uint256 _slash = _seized.div(TBTCConstants.getFundingFraudPartialSlashDivisor());
_d.pushFundsToKeepGroup(_seized.sub(_slash));
_d.depositOwner().transfer(_slash);
}

/// @notice Seizes signer bonds and distributes them to the funder.
/// @dev This is only called as part of funding fraud flow.
function distributeSignerBondsToFunder(DepositUtils.Deposit storage _d) internal {
Expand Down Expand Up @@ -140,6 +131,7 @@ library DepositFunding {
_d.setFailedSetup();
_d.logSetupFailed();

_d.closeKeep();
fundingTeardown(_d);
}

Expand Down Expand Up @@ -168,84 +160,10 @@ library DepositFunding {
bool _isFraud = _d.submitSignatureFraud(_v, _r, _s, _signedDigest, _preimage);
require(_isFraud, "Signature is not fraudulent");
_d.logFraudDuringSetup();

// If the funding timeout has elapsed, punish the funder too!
if (block.timestamp > _d.fundingProofTimerStart.add(TBTCConstants.getFundingTimeout())) {
_d.setFailedSetup();
} else {
/* NB: This is reuse of the variable */
_d.fundingProofTimerStart = block.timestamp;
_d.setFraudAwaitingBTCFundingProof();
}
}

/// @notice Anyone may notify the contract no funding proof was submitted during funding fraud.
/// @dev This is not a funder fault. The signers have faulted, so the funder shouldn't fund.
/// @param _d Deposit storage pointer.
function notifyFraudFundingTimeout(DepositUtils.Deposit storage _d) public {
require(
_d.inFraudAwaitingBTCFundingProof(),
"Not currently awaiting fraud-related funding proof"
);
require(
block.timestamp > _d.fundingProofTimerStart.add(TBTCConstants.getFraudFundingTimeout()),
"Fraud funding proof timeout has not elapsed"
);
_d.setFailedSetup();
_d.logSetupFailed();

partiallySlashForFraudInFunding(_d);
distributeSignerBondsToFunder(_d);

Choose a reason for hiding this comment

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

Note: funder can cause this to fail and potentially push a fraudulent deposit into an active state.

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, this feeds into the overall “push vs pull” question noted in a few other places as well:

fundingFraudTeardown(_d);
}

/// @notice Anyone may notify the deposit of a funding proof during funding fraud.
// We reward the funder the entire bond if this occurs.
/// @dev Takes a pre-parsed transaction and calculates values needed to verify funding.
/// @param _d Deposit storage pointer.
/// @param _txVersion Transaction version number (4-byte LE).
/// @param _txInputVector All transaction inputs prepended by the number of inputs encoded as a VarInt, max 0xFC(252) inputs.
/// @param _txOutputVector All transaction outputs prepended by the number of outputs encoded as a VarInt, max 0xFC(252) outputs.
/// @param _txLocktime Final 4 bytes of the transaction.
/// @param _fundingOutputIndex Index of funding output in _txOutputVector (0-indexed).
/// @param _merkleProof The merkle proof of transaction inclusion in a block.
/// @param _txIndexInBlock Transaction index in the block (0-indexed).
/// @param _bitcoinHeaders Single bytestring of 80-byte bitcoin headers, lowest height first.
/// @return True if no errors are thrown.
function provideFraudBTCFundingProof(
DepositUtils.Deposit storage _d,
bytes4 _txVersion,
bytes memory _txInputVector,
bytes memory _txOutputVector,
bytes4 _txLocktime,
uint8 _fundingOutputIndex,
bytes memory _merkleProof,
uint256 _txIndexInBlock,
bytes memory _bitcoinHeaders
) public returns (bool) {
require(_d.inFraudAwaitingBTCFundingProof(), "Not awaiting a funding proof during setup fraud");

bytes8 _valueBytes;
bytes memory _utxoOutpoint;

(_valueBytes, _utxoOutpoint) = _d.validateAndParseFundingSPVProof(
_txVersion,
_txInputVector,
_txOutputVector,
_txLocktime,
_fundingOutputIndex,
_merkleProof,
_txIndexInBlock,
_bitcoinHeaders
);

_d.setFailedSetup();
_d.logSetupFailed();

// If the proof is accepted, update to failed, and distribute signer bonds
distributeSignerBondsToFunder(_d);
fundingFraudTeardown(_d);

return true;
}

/// @notice Anyone may notify the deposit of a funding proof to activate the deposit.
Expand Down
2 changes: 1 addition & 1 deletion solidity/contracts/deposit/DepositLiquidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ library DepositLiquidation {
bytes memory _preimage
) public {
require(
!_d.inFunding() && !_d.inFundingFailure(),
!_d.inFunding(),
"Use provideFundingECDSAFraudProof instead"
);
require(
Expand Down
10 changes: 1 addition & 9 deletions solidity/contracts/deposit/DepositRedemption.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ library DepositRedemption {
_keep.distributeERC20Reward(address(_d.tbtcToken), _d.signerFee());
}

/// @notice Closes keep associated with the deposit.
/// @dev Should be called when the keep is no longer needed and the signing
/// group can disband.
function closeKeep(DepositUtils.Deposit storage _d) internal {
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress);
_keep.closeKeep();
}

/// @notice Approves digest for signing by a keep.
/// @dev Calls given keep to sign the digest. Records a current timestamp
/// for given digest.
Expand Down Expand Up @@ -321,7 +313,7 @@ library DepositRedemption {

// Transfer TBTC to signers and close the keep.
distributeSignerFee(_d);
closeKeep(_d);
_d.closeKeep();

_d.distributeFeeRebate();

Expand Down
17 changes: 0 additions & 17 deletions solidity/contracts/deposit/DepositStates.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ library DepositStates {
AWAITING_BTC_FUNDING_PROOF,

// FAILED SETUP
FRAUD_AWAITING_BTC_FUNDING_PROOF,
FAILED_SETUP,

// ACTIVE
Expand Down Expand Up @@ -42,14 +41,6 @@ library DepositStates {
);
}

/// @notice Check if the contract is currently in the funding faud flow.
/// @dev This checks for the flow, not the SETUP_FAILED termination state.
/// @param _d Deposit storage pointer.
/// @return True if contract is currently in the funding fraud flow else False.
function inFundingFailure(DepositUtils.Deposit storage _d) public view returns (bool) {
return (_d.currentState == uint8(States.FRAUD_AWAITING_BTC_FUNDING_PROOF));
}

/// @notice Check if the contract is currently in the signer liquidation flow.
/// @dev This could be caused by fraud, or by an unfilled margin call.
/// @param _d Deposit storage pointer.
Expand Down Expand Up @@ -111,10 +102,6 @@ library DepositStates {
return _d.currentState == uint8(States.AWAITING_BTC_FUNDING_PROOF);
}

function inFraudAwaitingBTCFundingProof(DepositUtils.Deposit storage _d) external view returns (bool) {
return _d.currentState == uint8(States.FRAUD_AWAITING_BTC_FUNDING_PROOF);
}

function inFailedSetup(DepositUtils.Deposit storage _d) external view returns (bool) {
return _d.currentState == uint8(States.FAILED_SETUP);
}
Expand Down Expand Up @@ -159,10 +146,6 @@ library DepositStates {
_d.currentState = uint8(States.AWAITING_BTC_FUNDING_PROOF);
}

function setFraudAwaitingBTCFundingProof(DepositUtils.Deposit storage _d) external {
_d.currentState = uint8(States.FRAUD_AWAITING_BTC_FUNDING_PROOF);
}

function setFailedSetup(DepositUtils.Deposit storage _d) external {
_d.currentState = uint8(States.FAILED_SETUP);
}
Expand Down
8 changes: 8 additions & 0 deletions solidity/contracts/deposit/DepositUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ library DepositUtils {
mapping (bytes32 => uint256) approvedDigests;
}

/// @notice Closes keep associated with the deposit.
/// @dev Should be called when the keep is no longer needed and the signing
/// group can disband.
function closeKeep(DepositUtils.Deposit storage _d) internal {
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress);
_keep.closeKeep();
}

/// @notice Gets the current block difficulty.
/// @dev Calls the light relay and gets the current block difficulty.
/// @return The difficulty.
Expand Down
Loading