-
Notifications
You must be signed in to change notification settings - Fork 42
Refactor IKeep/KeepBridge #268
Changes from 42 commits
9867947
64778d8
6d53832
18a8e3a
c5094a4
de8d48a
9c58fab
c683879
6f272de
66ff1d8
cac0213
a96a3fe
4e23d40
c2550be
40cacc4
ec3ee18
fd61c97
cdc5f41
57efbcb
1b29c2d
c215b42
eb592c3
cbb2e67
af677ca
0f48473
ed528b0
8ee4484
9c4cac0
33811d3
4fb3778
ec3b7a5
a04b5e7
f985dc7
b35a401
64a54b7
2e208d9
6560d55
e5de8e7
1cb90a8
675fa69
3440afb
d507ac7
5832ca7
b51bffe
4ea17c4
5b6cdd0
aef6b32
eb5fc4b
d9cf615
e9d3724
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,11 @@ pragma solidity ^0.5.10; | |
import {SafeMath} from "bitcoin-spv/contracts/SafeMath.sol"; | ||
import {BytesLib} from "bitcoin-spv/contracts/BytesLib.sol"; | ||
import {BTCUtils} from "bitcoin-spv/contracts/BTCUtils.sol"; | ||
|
||
import {IECDSAKeep} from "keep-tecdsa/solidity/contracts/api/IECDSAKeep.sol"; | ||
|
||
import {TBTCToken} from "../system/TBTCToken.sol"; | ||
import {IKeep} from "../interfaces/IKeep.sol"; | ||
import {TBTCSystem} from "../system/TBTCSystem.sol"; | ||
import {DepositUtils} from "./DepositUtils.sol"; | ||
import {DepositLiquidation} from "./DepositLiquidation.sol"; | ||
import {DepositStates} from "./DepositStates.sol"; | ||
|
@@ -39,17 +42,6 @@ library DepositFunding { | |
_d.signingGroupPubkeyY = bytes32(0); | ||
} | ||
|
||
/// @notice get the signer pubkey for our keep | ||
/// @dev calls out to the keep contract, should get 64 bytes back | ||
/// @return the 64 byte pubkey | ||
function getKeepPubkeyResult(DepositUtils.Deposit storage _d) public view returns (bytes memory) { | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
bytes memory _pubkey = _keep.getKeepPubkey(_d.keepAddress); | ||
/* solium-disable-next-line */ | ||
require(_pubkey.length == 64, "public key not set or not 64-bytes long"); | ||
return _pubkey; | ||
} | ||
|
||
/// @notice The system can spin up a new deposit | ||
/// @dev This should be called by an approved contract, not a developer | ||
/// @param _d deposit storage pointer | ||
|
@@ -63,10 +55,10 @@ library DepositFunding { | |
) public returns (bool) { | ||
require(_d.inStart(), "Deposit setup already requested"); | ||
|
||
IKeep _keep = IKeep(_d.KeepBridge); | ||
|
||
// TODO: Whole value is forwarded to TBTC System, but should be partially | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually currently it's stored in deposit as funder bond but we need to transfer part of it to the keep as per #297. I've updated the comment. |
||
// stored as funder's bond in the deposit https://github.com/keep-network/tbtc/issues/279. | ||
/* solium-disable-next-line value-in-payable */ | ||
_d.keepAddress = _keep.requestNewKeep.value(msg.value)(_m, _n); // kinda gross but | ||
_d.keepAddress = TBTCSystem(_d.TBTCSystem).requestNewKeep.value(msg.value)(_m, _n); // kinda gross but | ||
_d.signingGroupRequestedAt = block.timestamp; | ||
|
||
_d.setAwaitingSignerSetup(); | ||
|
@@ -150,10 +142,12 @@ library DepositFunding { | |
/// @return True if successful, otherwise revert | ||
function retrieveSignerPubkey(DepositUtils.Deposit storage _d) public { | ||
require(_d.inAwaitingSignerSetup(), "Not currently awaiting signer setup"); | ||
bytes memory _keepResult = getKeepPubkeyResult(_d); | ||
|
||
_d.signingGroupPubkeyX = _keepResult.slice(0, 32).toBytes32(); | ||
_d.signingGroupPubkeyY = _keepResult.slice(32, 32).toBytes32(); | ||
bytes memory _publicKey = IECDSAKeep(_d.keepAddress).getPublicKey(); | ||
require(_publicKey.length == 64, "public key not set or not 64-bytes long"); | ||
|
||
_d.signingGroupPubkeyX = _publicKey.slice(0, 32).toBytes32(); | ||
_d.signingGroupPubkeyY = _publicKey.slice(32, 32).toBytes32(); | ||
require(_d.signingGroupPubkeyY != bytes32(0) && _d.signingGroupPubkeyX != bytes32(0), "Keep returned bad pubkey"); | ||
_d.fundingProofTimerStart = block.timestamp; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,8 @@ import {BytesLib} from "bitcoin-spv/contracts/BytesLib.sol"; | |
import {ValidateSPV} from "bitcoin-spv/contracts/ValidateSPV.sol"; | ||
import {CheckBitcoinSigs} from "bitcoin-spv/contracts/SigCheck.sol"; | ||
import {DepositUtils} from "./DepositUtils.sol"; | ||
import {IKeep} from "../interfaces/IKeep.sol"; | ||
import {IBondedECDSAKeep} from "../external/IBondedECDSAKeep.sol"; | ||
import {IECDSAKeep} from "keep-tecdsa/solidity/contracts/api/IECDSAKeep.sol"; | ||
import {DepositStates} from "./DepositStates.sol"; | ||
import {OutsourceDepositLogging} from "./OutsourceDepositLogging.sol"; | ||
import {TBTCConstants} from "./TBTCConstants.sol"; | ||
|
@@ -33,19 +34,20 @@ library DepositRedemption { | |
address _tbtcTokenAddress = _d.TBTCToken; | ||
TBTCToken _tbtcToken = TBTCToken(_tbtcTokenAddress); | ||
|
||
IKeep _keep = IKeep(_d.KeepBridge); | ||
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress); | ||
|
||
_tbtcToken.approve(_d.KeepBridge, DepositUtils.signerFee()); | ||
_tbtcToken.approve(_d.keepAddress, DepositUtils.signerFee()); | ||
_keep.distributeERC20ToKeepGroup(_d.keepAddress, _tbtcTokenAddress, DepositUtils.signerFee()); | ||
} | ||
|
||
/// @notice approves a digest for signing by our keep group | ||
/// @dev calls out to the keep contract | ||
/// @param _digest the digest to approve | ||
/// @return true if approved, otherwise revert | ||
function approveDigest(DepositUtils.Deposit storage _d, bytes32 _digest) public returns (bool) { | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
return _keep.approveDigest(_d.keepAddress, _digest); | ||
/// @notice Approves digest for signing by a keep | ||
/// @dev Calls given keep to sign the digest. Records a current timestamp | ||
/// for given digest | ||
/// @param _digest Digest to approve | ||
function approveDigest(DepositUtils.Deposit storage _d, bytes32 _digest) internal { | ||
IECDSAKeep(_d.keepAddress).sign(_digest); | ||
|
||
_d.approvedDigests[_digest] = block.timestamp; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we practice defensive programming in our codebase (thinking about @pdyraga's comment earlier 😉)? Should we assert the digest hasn't already been approved? ie:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about this. It's an internal function and we use it in a specific context of redemption. |
||
} | ||
|
||
function redemptionTBTCBurn(DepositUtils.Deposit storage _d) private { | ||
|
@@ -93,7 +95,8 @@ library DepositRedemption { | |
_d.initialRedemptionFee = _requestedFee; | ||
_d.withdrawalRequestTime = block.timestamp; | ||
_d.lastRequestedDigest = _sighash; | ||
require(approveDigest(_d, _sighash), "Keep returned false"); | ||
|
||
approveDigest(_d, _sighash); | ||
|
||
_d.setAwaitingWithdrawalSignature(); | ||
_d.logRedemptionRequested( | ||
|
@@ -168,7 +171,8 @@ library DepositRedemption { | |
// Ratchet the signature and redemption proof timeouts | ||
_d.withdrawalRequestTime = block.timestamp; | ||
_d.lastRequestedDigest = _sighash; | ||
require(approveDigest(_d, _sighash), "Keep returned false"); | ||
|
||
approveDigest(_d, _sighash); | ||
NicholasDotSol marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Go back to waiting for a signature | ||
_d.setAwaitingWithdrawalSignature(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ import {BytesLib} from "bitcoin-spv/contracts/BytesLib.sol"; | |
import {TBTCConstants} from "./TBTCConstants.sol"; | ||
import {ITBTCSystem} from "../interfaces/ITBTCSystem.sol"; | ||
import {IERC721} from "../interfaces/IERC721.sol"; | ||
import {IKeep} from "../interfaces/IKeep.sol"; | ||
import {IBondedECDSAKeep} from "../external/IBondedECDSAKeep.sol"; | ||
import {TBTCToken} from "../system/TBTCToken.sol"; | ||
|
||
library DepositUtils { | ||
|
@@ -24,7 +24,6 @@ library DepositUtils { | |
// SET DURING CONSTRUCTION | ||
address TBTCSystem; | ||
address TBTCToken; | ||
address KeepBridge; | ||
uint8 currentState; | ||
|
||
// SET ON FRAUD | ||
|
@@ -51,6 +50,11 @@ library DepositUtils { | |
bytes8 utxoSizeBytes; // LE uint. the size of the deposit UTXO in satoshis | ||
uint256 fundedAt; // timestamp when funding proof was received | ||
bytes utxoOutpoint; // the 36-byte outpoint of the custodied UTXO | ||
|
||
/// @notice Map of timestamps for transaction digests approved for signing | ||
/// @dev Holds a timestamp from the moment when the transaction digest | ||
/// was approved for signing | ||
mapping (bytes32 => uint256) approvedDigests; | ||
liamzebedee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// @notice Gets the current block difficulty | ||
|
@@ -363,7 +367,7 @@ library DepositUtils { | |
/// @dev Calls the keep contract to do so | ||
/// @return The amount of bonded ETH in wei | ||
function fetchBondAmount(Deposit storage _d) public view returns (uint256) { | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress); | ||
return _keep.checkBondAmount(_d.keepAddress); | ||
} | ||
|
||
|
@@ -374,13 +378,13 @@ library DepositUtils { | |
return abi.encodePacked(_b).reverseEndianness().bytesToUint(); | ||
} | ||
|
||
/// @notice determines whether a digest has been approved for our keep group | ||
/// @dev calls out to the keep contract, storing a 256bit int costs the same as a bool | ||
/// @param _digest the digest to check approval time for | ||
/// @return the time it was approved. 0 if unapproved | ||
/// @notice Gets timestamp of digest approval for signing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fix up formatting :) |
||
/// @dev Identifies entry in the recorded approvals by keep ID and digest pair | ||
/// @param _digest Digest to check approval for | ||
/// @return Timestamp from the moment of recording the digest for signing. | ||
/// Returns 0 if the digest was not approved for signing | ||
function wasDigestApprovedForSigning(Deposit storage _d, bytes32 _digest) public view returns (uint256) { | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
return _keep.wasDigestApprovedForSigning(_d.keepAddress, _digest); | ||
return _d.approvedDigests[_digest]; | ||
} | ||
|
||
/// @notice Looks up the deposit beneficiary by calling the tBTC system | ||
|
@@ -406,7 +410,7 @@ library DepositUtils { | |
/// @return the amount of ether seized | ||
function seizeSignerBonds(Deposit storage _d) public returns (uint256) { | ||
uint256 _preCallBalance = address(this).balance; | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress); | ||
_keep.seizeSignerBonds(_d.keepAddress); | ||
uint256 _postCallBalance = address(this).balance; | ||
require(_postCallBalance > _preCallBalance, "No funds received, unexpected"); | ||
|
@@ -428,7 +432,7 @@ library DepositUtils { | |
/// @return true if successful, otherwise revert | ||
function pushFundsToKeepGroup(Deposit storage _d, uint256 _ethValue) public returns (bool) { | ||
require(address(this).balance >= _ethValue, "Not enough funds to send"); | ||
IKeep _keep = IKeep(_d.KeepBridge); | ||
IBondedECDSAKeep _keep = IBondedECDSAKeep(_d.keepAddress); | ||
return _keep.distributeEthToKeepGroup.value(_ethValue)(_d.keepAddress); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,8 @@ | ||
pragma solidity ^0.5.10; | ||
|
||
/** | ||
* @title Keep interface | ||
*/ | ||
|
||
interface IKeep { | ||
|
||
// request a new m-of-n group | ||
// should return a unique keep contract address | ||
function requestNewKeep(uint256 _m, uint256 _n) external payable returns (address _keepAddress); | ||
|
||
// get the result of a keep formation | ||
// should return a 64 byte packed pubkey (x and y) | ||
// error if not ready yet | ||
function getKeepPubkey(address _keepAddress) external view returns (bytes memory); | ||
|
||
/// @notice Approves digest for signing. | ||
/// @param _keepAddress Keep address | ||
/// @param _digest Digest to sign | ||
/// @return True if successful. | ||
function approveDigest(address _keepAddress, bytes32 _digest) external returns (bool _success); | ||
|
||
/// @notice Gets timestamp of digest approval for signing. | ||
/// @param _keepAddress Keep address | ||
/// @param _digest Digest to sign | ||
/// @return Timestamp from the moment of recording the digest for signing. | ||
/// Returns 0 if the digest was not recorded for signing for the given keep. | ||
function wasDigestApprovedForSigning(address _keepAddress, bytes32 _digest) external view returns (uint256); | ||
|
||
// TODO: This is a contract holding functions which are required to be implemented | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. comment is a little confusing, what about:
|
||
// on keep side and added to IBondedECDSAKeep interface. | ||
interface IBondedECDSAKeep { | ||
// Expected behavior: | ||
// Error if not fraud | ||
// Return true if fraud | ||
|
@@ -47,7 +22,7 @@ interface IKeep { | |
|
||
// Allow sending tokens to a keep group | ||
// Useful for sending signers their TBTC | ||
// The Keep contract should call transferFrom on the token contrcact | ||
// The Keep contract should call transferFrom on the token contract | ||
function distributeERC20ToKeepGroup(address _keepAddress, address _asset, uint256 _value) external returns (bool); | ||
|
||
// returns the amount of the keep's ETH bond in wei | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder - can we tweak it in #57 to have it exported to some other directory structure? For example, to have here just:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to do that, but unfortunately, due to npm limitations, we would need to change the structure to have
api
directory in the root dir ofkeep-tecdsa
or do some magic scripting workaround. Let's discuss it in keep-network/keep-ecdsa#57 if you think it's needed.