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

Refund funder if signer setup fails #520

Merged
merged 15 commits into from Mar 27, 2020
1 change: 0 additions & 1 deletion solidity/contracts/deposit/Deposit.sol
Expand Up @@ -255,7 +255,6 @@ contract Deposit is DepositFactoryAuthority {
//

/// @notice Anyone may notify the contract that signing group setup has timed out.
/// @dev We rely on the keep system punishes the signers in this case.
/// @return True if successful, otherwise revert.
function notifySignerSetupFailure() public returns (bool) {
self.notifySignerSetupFailure();
Expand Down
10 changes: 9 additions & 1 deletion solidity/contracts/deposit/DepositFunding.sol
Expand Up @@ -65,6 +65,7 @@ library DepositFunding {
uint256 _bondRequirementSatoshi = _lotSizeSatoshis.mul(_system.getInitialCollateralizedPercent()).div(100);
uint256 _bondRequirementWei = _d.fetchBitcoinPrice().mul(_bondRequirementSatoshi);

_d.keepSetupFee = _system.createNewDepositFeeEstimate();
/* solium-disable-next-line value-in-payable */
_d.keepAddress = _system.requestNewKeep.value(msg.value)(_m, _n, _bondRequirementWei);
_d.signerFeeDivisor = _system.getSignerFeeDivisor();
Expand Down Expand Up @@ -96,14 +97,21 @@ library DepositFunding {
}

/// @notice Anyone may notify the contract that signing group setup has timed out.
/// @dev We rely on the keep system to punish the signers in this case.
/// @param _d Deposit storage pointer.
function notifySignerSetupFailure(DepositUtils.Deposit storage _d) public {
require(_d.inAwaitingSignerSetup(), "Not awaiting setup");
require(
block.timestamp > _d.signingGroupRequestedAt.add(TBTCConstants.getSigningGroupFormationTimeout()),
"Signing group formation timeout not yet elapsed"
);

// refund the deposit owner the cost to create a new keep at current price levels.
uint256 _seized = _d.seizeSignerBonds();

/* solium-disable-next-line security/no-send */
_d.depositOwner().send(_d.keepSetupFee);

Choose a reason for hiding this comment

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

If possible, this should be a pull payment.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to merge this branch and have us consider the pull payment aspect holistically across the codebase next week.

Copy link
Contributor

Choose a reason for hiding this comment

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

This landed in #570.

_d.pushFundsToKeepGroup(_seized.sub(_d.keepSetupFee));

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

Expand Down
1 change: 1 addition & 0 deletions solidity/contracts/deposit/DepositUtils.sol
Expand Up @@ -36,6 +36,7 @@ library DepositUtils {
uint128 initialCollateralizedPercent;
uint128 undercollateralizedThresholdPercent;
uint128 severelyUndercollateralizedThresholdPercent;
uint256 keepSetupFee;

// SET ON FRAUD
uint256 liquidationInitiated; // Timestamp of when liquidation starts
Expand Down
4 changes: 4 additions & 0 deletions solidity/contracts/test/deposit/TestDeposit.sol
Expand Up @@ -63,6 +63,10 @@ contract TestDeposit is Deposit {
self.signerFeeDivisor = _signerFeeDivisor;
}

function setKeepSetupFee(uint256 _fee) public {
self.keepSetupFee = _fee;
}

function getSignerFeeDivisor() public view returns (uint256) { return self.signerFeeDivisor; }

function setLotSize(uint256 _lotSizeSatoshis) public {
Expand Down
38 changes: 36 additions & 2 deletions solidity/test/DepositFundingTest.js
Expand Up @@ -6,6 +6,7 @@ const {BN, constants, expectRevert} = require("@openzeppelin/test-helpers")
const {ZERO_ADDRESS} = constants
const {expect} = require("chai")
const ECDSAKeepStub = contract.fromArtifact("ECDSAKeepStub")
const TBTCSystem = contract.fromArtifact("TBTCSystem")

// spare signature:
// signing with privkey '11' * 32
Expand Down Expand Up @@ -50,6 +51,7 @@ describe("DepositFunding", async function() {
let tbtcDepositToken
let testDeposit
let ecdsaKeepStub
let ecdsaKeepFactory

let fundingProofTimerStart
let beneficiary
Expand All @@ -66,8 +68,10 @@ describe("DepositFunding", async function() {
tbtcDepositToken,
testDeposit,
ecdsaKeepStub,
ecdsaKeepFactoryStub,
} = await deployAndLinkAll())

ecdsaKeepFactory = ecdsaKeepFactoryStub
beneficiary = accounts[4]
await tbtcDepositToken.forceMint(
beneficiary,
Expand Down Expand Up @@ -172,29 +176,59 @@ describe("DepositFunding", async function() {
)
})
})

describe("notifySignerSetupFailure", async () => {
let timer
let owner
let openKeepFee
before(async () => {})

before(async () => {
;({
tbtcConstants,
mockRelay,
tbtcSystemStub,
tbtcToken,
tbtcDepositToken,
testDeposit,
ecdsaKeepStub,
} = await deployAndLinkAll([], {TBTCSystemStub: TBTCSystem}))

openKeepFee = await ecdsaKeepFactory.openKeepFeeEstimate.call()
await testDeposit.setKeepSetupFee(openKeepFee)
owner = accounts[1]
await tbtcDepositToken.forceMint(
owner,
web3.utils.toBN(testDeposit.address),
)
timer = await tbtcConstants.getSigningGroupFormationTimeout.call()
})

beforeEach(async () => {
const block = await web3.eth.getBlock("latest")
const blockTimestamp = block.timestamp
const value = openKeepFee + 100

await ecdsaKeepStub.send(value)

fundingProofTimerStart = blockTimestamp - timer.toNumber() - 1

await testDeposit.setState(states.AWAITING_SIGNER_SETUP)

await testDeposit.setFundingProofTimerStart(fundingProofTimerStart)
})

it("updates state to setup failed, deconstes state, and logs SetupFailed", async () => {
it("updates state to setup failed, deconstes state, logs SetupFailed, and refunds TDT owner", async () => {
const initialFunderBalance = await web3.eth.getBalance(owner)
const blockNumber = await web3.eth.getBlock("latest").number
await testDeposit.notifySignerSetupFailure()

const signingGroupRequestedAt = await testDeposit.getSigningGroupRequestedAt.call()
const finalFunderBalance = await web3.eth.getBalance(owner)

expect(
new BN(finalFunderBalance).sub(new BN(initialFunderBalance)),
).to.eq.BN(openKeepFee)

expect(
signingGroupRequestedAt,
"signingGroupRequestedAt should be 0",
Expand Down