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

Uniswap integration #160

Closed
wants to merge 86 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
8e774e7
Add Uniswap contracts as git submodule
liamzebedee Jun 9, 2019
b1489aa
Add README and Seth deploy script
liamzebedee Jun 9, 2019
6e15c3b
Added Uniswap interface definitions in Sol
liamzebedee Jun 9, 2019
46a8c96
Deploy script now uses separate files for addresses
liamzebedee Jun 9, 2019
8b2ee5f
Add TBTCSystemStub.setup and save uniswap factory
liamzebedee Jun 9, 2019
f6fa7b3
Rename Uniswap interfaces to more be more terse
liamzebedee Jun 9, 2019
9f89aa5
Add TBTC ERC20 token and createExchange
liamzebedee Jun 9, 2019
756b93f
Uniswap deployment now automatic in Truffle migration
liamzebedee Jun 10, 2019
88eb55e
Add openzeppelin 2.0 for token contracts
liamzebedee Jun 10, 2019
1fa9333
Extend TBTC from OpenZeppelin contracts and deploy
liamzebedee Jun 10, 2019
8af7289
Fix TBTCSystemStub.setup (bad git- iquette)
liamzebedee Jun 10, 2019
e47cb93
Fixed Uniswap migration to work with truffle tests
liamzebedee Jun 10, 2019
63eb812
Test Uniswap and TBTC is deployed
liamzebedee Jun 10, 2019
393cd00
Test for Uniswap e2e trade with TBTC
liamzebedee Jun 11, 2019
f80d08e
Fix Uniswap deploy script env vars
liamzebedee Jun 12, 2019
8f49752
Refactor uniswap deploys separate from TBTCSystem
liamzebedee Jun 13, 2019
48a16c6
Add Remix command for debugging
liamzebedee Jun 13, 2019
603c3c9
Better design for storing/testing Uniswap deploys
liamzebedee Jun 13, 2019
01fc708
Merge branch 'onchain-liquidation' of github.com:keep-network/tbtc in…
liamzebedee Jun 21, 2019
3f2a224
Uniswap migrated purely through Truffle now
liamzebedee Jun 21, 2019
a2ca3f7
KeepStub should implement IKeep
liamzebedee Jun 21, 2019
064fa4c
Add _d Deposit param to attemptToLiquidateOnchain
liamzebedee Jun 21, 2019
5d3dec3
Expose attemptToLiquidateOnchain
liamzebedee Jun 21, 2019
d29d02b
Failing test for attemptToLiquidateOnchain
liamzebedee Jun 21, 2019
56445a8
Remember to include changes to Uniswap deployment
liamzebedee Jun 21, 2019
9edf4d6
Use TBTC instead of TBTCStub in uniswap test
liamzebedee Jun 23, 2019
0f5ea65
Create exchange in deployment only
liamzebedee Jun 23, 2019
8335067
Use setExteroriorAddresses instead of setup
liamzebedee Jun 23, 2019
baf4a9e
Add clean command
liamzebedee Jun 23, 2019
cc28f50
Move UniswapHelpers into separate file
liamzebedee Jun 24, 2019
af77695
Remove old NODE_ENV migration speedup hack
liamzebedee Jun 24, 2019
26bc55e
Deploy Uniswap with mock TBTC as part of test
liamzebedee Jun 24, 2019
f0d91ad
Rename uniswap test to test naming to find easier
liamzebedee Jun 25, 2019
91465d3
Add calcWithFee helper for uniswap
liamzebedee Jun 25, 2019
4398801
Calc eth swap value with Uniswap fee
liamzebedee Jun 25, 2019
9cd1acc
Pre-check balances to aid in future potential debugs
liamzebedee Jun 25, 2019
c1dcd20
Remove old Web3 code, add notes on uniswap
liamzebedee Jun 25, 2019
0e12f5b
Tidy up migrations code
liamzebedee Jun 25, 2019
811fe11
Failing attemptToLiquidateOnchain impl w/out fee
liamzebedee Jun 25, 2019
6a8a7e2
Add setExteroriorAddresses to SystemStub
liamzebedee Jun 25, 2019
70e3246
attemptToLiquidateOnchain test passing!
liamzebedee Jun 25, 2019
223a077
Clean up Uniswap code
liamzebedee Jun 26, 2019
10e2260
Merge from master
liamzebedee Jun 26, 2019
e39c087
Manually add Vyper events to Solidity contract
liamzebedee Jun 26, 2019
13f8b3a
Fixed accidental bug intro'd by redefining expect
liamzebedee Jun 26, 2019
a1d5e32
attemptToLiquidateOnchain tests for Uniswap event
liamzebedee Jun 26, 2019
31207de
Doc UniswapDeployment
liamzebedee Jun 26, 2019
9ece9f5
Fix missing redemption flow logic in "abort" flow
liamzebedee Jun 26, 2019
655a963
Merge master
liamzebedee Jul 10, 2019
205f8a8
Fix SystemStub->TBTCSystemStub merge errors
liamzebedee Jul 10, 2019
9efd8b5
Add UniswapExchangeStub
liamzebedee Jul 11, 2019
9090ea7
Fix Uniswap exchange stubbing
liamzebedee Jul 11, 2019
471ed0d
Simplify attemptToLiquidateOnchain test
liamzebedee Jul 11, 2019
7430c26
Flesh out tests for liquidation flows
liamzebedee Jul 11, 2019
b028a55
UniswapExchangeStub now working in tests
liamzebedee Jul 11, 2019
9b00756
Add startSignerFraudLiquidation,startSignerAbortLiquidation
liamzebedee Jul 11, 2019
61f5fda
Stub distributeEthToKeepGroup
liamzebedee Jul 11, 2019
0ab419a
Helper for asserting balances
liamzebedee Jul 14, 2019
3d95b77
Failing test for startSignerFraudLiquidation
liamzebedee Jul 14, 2019
3571377
Upgrade Babel and log async stack traces!
liamzebedee Jul 15, 2019
2a8b622
Fix AssertBalanceHelpers
liamzebedee Jul 15, 2019
45db78b
Replace with Nich's token impl
liamzebedee Jul 15, 2019
38f4319
Implemented new startSignerFraudLiquidation logic
liamzebedee Jul 15, 2019
78acc02
Fixed UniswapExchangeStub
liamzebedee Jul 15, 2019
189b7c6
startSignerFraudLiquidation test now passing
liamzebedee Jul 15, 2019
4dfcdac
getTBTCUniswapExchange -> getUniswapFactory
liamzebedee Jul 16, 2019
dd72854
Extracted liquidation flow tests into new test file
liamzebedee Jul 16, 2019
c9fb027
Solidity coverage
liamzebedee Jul 17, 2019
5938dfd
Bad copy-paste
liamzebedee Jul 17, 2019
82aab63
Send only exact beneficiary reward
liamzebedee Jul 17, 2019
6abbfaf
Use requestorAddr directly for redemption check
liamzebedee Jul 17, 2019
887c100
Remove unneeded checks
liamzebedee Jul 17, 2019
2ee362f
New TestDepositLiquidation mock
liamzebedee Jul 17, 2019
5459bf0
Much cleaner test structure, back with startSignerFraudLiquidation
liamzebedee Jul 17, 2019
a3cb6a8
Changed getUniswapFactory to external
liamzebedee Jul 17, 2019
6819e9a
Passing startSignerFraudLiquidation after refactor
liamzebedee Jul 17, 2019
364cf02
Common liquidation flow - startLiquidation
liamzebedee Jul 17, 2019
255b2e9
startLiquidation fully tested
liamzebedee Jul 18, 2019
384b877
Leftover eth from liquidation
liamzebedee Jul 19, 2019
d2a01f2
Add getTxCost helper
liamzebedee Jul 19, 2019
7688c51
Asserting that maintainer receives eth refund
liamzebedee Jul 19, 2019
0cd33ad
Cleanup
liamzebedee Jul 19, 2019
3378a52
Define maintainer for all tests
liamzebedee Jul 19, 2019
0a2f0de
Fix BN assertion
liamzebedee Jul 19, 2019
922bd68
Fix "has no liquidity by default" test
liamzebedee Jul 19, 2019
091bbc9
Introduced real Uniswap exchange in tests, calc fees
liamzebedee Jul 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
path = implementation/contracts/bitcoin-spv
url = [email protected]:summa-tx/bitcoin-spv.git
branch = 1.0.0-embedabble
[submodule "implementation/uniswap/contracts-vyper"]
path = implementation/uniswap/contracts-vyper
url = https://github.com/Uniswap/contracts-vyper
branch = c10c08d81d6114f694baa8bd32f555a40f6264da
14 changes: 13 additions & 1 deletion implementation/.babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
{
"presets": ["es2015", "stage-2", "stage-3"]
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": 3,
"targets": {
"node": true
},
}
]
],
"sourceMaps": "inline"
}
2 changes: 2 additions & 0 deletions implementation/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ blocks/
__pycache__/
node_modules/
.mypy_cache
coverage/
coverage.json
2 changes: 2 additions & 0 deletions implementation/contracts/DepositLog.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ contract DepositLog {
/* solium-disable-next-line no-empty-blocks */
function approvedToLog(address _caller) public view returns (bool) {
/* TODO: auth via system */
_caller;
return true;
}

///
Expand Down
2 changes: 1 addition & 1 deletion implementation/contracts/deposit/DepositFunding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ library DepositFunding {
IKeep _keep = IKeep(_d.KeepBridge);
bytes memory _pubkey = _keep.getKeepPubkey(_d.keepID);
/* solium-disable-next-line */
require(_pubkey.length == 64);
require(_pubkey.length == 64, "public key not set or not 64-bytes long");
return _pubkey;
}

Expand Down
99 changes: 63 additions & 36 deletions implementation/contracts/deposit/DepositLiquidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {TBTCConstants} from "./TBTCConstants.sol";
import {IKeep} from "../interfaces/IKeep.sol";
import {OutsourceDepositLogging} from "./OutsourceDepositLogging.sol";
import {IBurnableERC20} from "../interfaces/IBurnableERC20.sol";
import {IUniswapFactory} from "../uniswap/IUniswapFactory.sol";
import {IUniswapExchange} from "../uniswap/IUniswapExchange.sol";
import {ITBTCSystem} from "../interfaces/ITBTCSystem.sol";

library DepositLiquidation {

Expand All @@ -21,8 +24,32 @@ library DepositLiquidation {
/// @notice Tries to liquidate the position on-chain using the signer bond
/// @dev Calls out to other contracts, watch for re-entrance
/// @return True if Liquidated, False otherwise
function attemptToLiquidateOnchain() public pure returns (bool) {
return false;
// TODO(liamz): make attemptToLiquidateOnchain internal, check for re-entry
function attemptToLiquidateOnchain(
DepositUtils.Deposit storage _d
) internal returns (bool) {
IUniswapFactory uniswapFactory = IUniswapFactory(ITBTCSystem(_d.TBTCSystem).getUniswapFactory());
IUniswapExchange exchange = IUniswapExchange(uniswapFactory.getExchange(_d.TBTCToken));
if(exchange == address(0x0)) {
return false;
}

// with collateralization = 125%, we can assume an order of
// 1.0005 TBTC (equivalent to will be filled
uint MIN_TBTC = TBTCConstants.getLotSize().add(DepositUtils.beneficiaryReward());

uint ethPrice = exchange.getTokenToEthInputPrice(MIN_TBTC);
uint uniswapFee = ethPrice * 1003 / 1000; // 0.3% fee
ethPrice += uniswapFee;

if(address(this).balance < ethPrice) {
return false;
}

uint deadline = block.timestamp + 1;
exchange.ethToTokenSwapOutput.value(ethPrice)(MIN_TBTC, deadline);

return true;
}

/// @notice Notifies the keep contract of fraud
Expand Down Expand Up @@ -72,58 +99,58 @@ library DepositLiquidation {
return (_bondValue.mul(100).div(_lotValue));
}

/// @notice Starts signer liquidation due to fraud
/// @dev We first attempt to liquidate on chain, then by auction
/// @param _d deposit storage pointer
function startSignerFraudLiquidation(DepositUtils.Deposit storage _d) public {
function startLiquidation(DepositUtils.Deposit storage _d) internal {
_d.logStartedLiquidation(true);

// Reclaim used state for gas savings
_d.redemptionTeardown();
uint256 _seized = _d.seizeSignerBonds();

if (_d.auctionTBTCAmount() == 0) {
// we came from the redemption flow
_d.setLiquidated();
_d.requesterAddress.transfer(_seized);
_d.logLiquidated();
return;
}

bool _liquidated = attemptToLiquidateOnchain();
_d.seizeSignerBonds();
bool _liquidated = attemptToLiquidateOnchain(_d);

if (_liquidated) {
_d.distributeBeneficiaryReward();
_d.setLiquidated();
_d.logLiquidated();
address(0).transfer(address(this).balance); // burn it down

_d.distributeBeneficiaryReward();

IBurnableERC20 _tbtc = IBurnableERC20(_d.TBTCToken);

if (_d.requesterAddress != address(0)) { // redemption
_tbtc.transferFrom(address(this), _d.requesterAddress, TBTCConstants.getLotSize());
} else {
// maintain supply peg
_tbtc.burnFrom(address(this), TBTCConstants.getLotSize());
}

} else if (!_liquidated) {
_d.liquidationInitiated = block.timestamp; // Store the timestamp for auction
}
if (!_liquidated) {
}


/// @notice Starts signer liquidation due to fraud
/// @dev We first attempt to liquidate on chain, then by auction
/// @param _d deposit storage pointer
function startSignerFraudLiquidation(DepositUtils.Deposit storage _d) public {
startLiquidation(_d);
if(_d.inLiquidated()) {
// send remaining eth to maintainer
msg.sender.transfer(address(this).balance);
} else {
_d.setFraudLiquidationInProgress();
_d.liquidationInitiated = block.timestamp; // Store the timestamp for auction
}
}

/// @notice Starts signer liquidation due to abort or undercollateralization
/// @dev We first attempt to liquidate on chain, then by auction
/// @param _d deposit storage pointer
function startSignerAbortLiquidation(DepositUtils.Deposit storage _d) public {
_d.logStartedLiquidation(false);
// Reclaim used state for gas savings
_d.redemptionTeardown();
_d.seizeSignerBonds();

bool _liquidated = attemptToLiquidateOnchain();

if (_liquidated) {
_d.distributeBeneficiaryReward();
startLiquidation(_d);
if(_d.inLiquidated()) {
// send remaining eth to signers
_d.pushFundsToKeepGroup(address(this).balance);
_d.setLiquidated();
_d.logLiquidated();
}
if (!_liquidated) {
_d.liquidationInitiated = block.timestamp; // Store the timestamp for auction
_d.setFraudLiquidationInProgress();
} else {
_d.setLiquidationInProgress();
}
}

Expand Down
2 changes: 1 addition & 1 deletion implementation/contracts/deposit/DepositUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ library DepositUtils {
function distributeBeneficiaryReward(Deposit storage _d) public {
IBurnableERC20 _tbtc = IBurnableERC20(_d.TBTCToken);
/* solium-disable-next-line */
require(_tbtc.transfer(depositBeneficiary(_d), _tbtc.balanceOf(address(this))));
require(_tbtc.transfer(depositBeneficiary(_d), beneficiaryReward()));
}

/// @notice pushes ether held by the deposit to the signer group
Expand Down
9 changes: 9 additions & 0 deletions implementation/contracts/interfaces/ITBTCSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ pragma solidity 0.4.25;

interface ITBTCSystem {

// Sets up the TBTC system
// - uniswap factory initialisation
// - TBTC uniswap exchange creation
function setExteroriorAddresses(
address _uniswapFactory,
address _tbtc
) external;

// expected behavior:
// return the price of 1 sat in wei
// these are the native units of the deposit contract
Expand All @@ -15,4 +23,5 @@ interface ITBTCSystem {
function fetchRelayCurrentDifficulty() external view returns (uint256);
function fetchRelayPreviousDifficulty() external view returns (uint256);

function getUniswapFactory() external view returns (address);
}
22 changes: 20 additions & 2 deletions implementation/contracts/interfaces/KeepBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ contract KeepBridge is IKeep {
// should return a 64 byte packed pubkey (x and y)
// error if not ready yet
function getKeepPubkey(uint256 _keepID) external view returns (bytes){
//TODO: Implement
return "";
// TODO: keepID type should be changed from uint256 to addrress
address _keepAddress = address(_keepID);

return ECDSAKeepContract(_keepAddress).getPublicKey();
}


Expand All @@ -74,9 +76,25 @@ contract KeepBridge is IKeep {
}
}

/// @notice Interface for communication with `KeepRegistry` contract
/// @dev It allows to call a function without the need of low-level call
interface KeepRegistryContract {

/// @notice Create a new ECDSA keep
/// @param _groupSize Number of members in the keep
/// @param _honestThreshold Minimum number of honest keep members
/// @return Created keep address
function createECDSAKeep(
uint256 _groupSize,
uint256 _honestThreshold
) external payable returns (address keep);
}

/// @notice Interface for communication with `ECDSAKeep` contract
/// @dev It allows to call a function without the need of low-level call
interface ECDSAKeepContract {

/// @notice Returns the keep signer's public key.
/// @return Signer's public key.
function getPublicKey() external view returns (bytes memory);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
pragma solidity 0.4.25;

import {ITBTCSystem} from "./ITBTCSystem.sol";
import {IERC721} from "./IERC721.sol";
import {ITBTCSystem} from "../interfaces/ITBTCSystem.sol";
import {IERC721} from "../interfaces/IERC721.sol";
import {DepositLog} from "../DepositLog.sol";
import {IUniswapFactory} from "../uniswap/IUniswapFactory.sol";
import {TBTC} from "../tokens/TBTC.sol";

contract TBTCSystemStub is ITBTCSystem, IERC721 {
contract TBTCSystem is ITBTCSystem, IERC721, DepositLog {

uint256 currentDifficulty = 1;
uint256 previousDifficulty = 1;
uint256 oraclePrice = 10 ** 12;
address depositOwner = address(0);

address public uniswapFactory;
address public tbtc;

function setExteroriorAddresses(
address _uniswapFactory,
address _tbtc
) external {
uniswapFactory = _uniswapFactory;
tbtc = _tbtc;
}

// Price Oracle
function fetchOraclePrice() external view returns (uint256) {return oraclePrice;}

Expand All @@ -23,6 +37,10 @@ contract TBTCSystemStub is ITBTCSystem, IERC721 {
return previousDifficulty;
}

function getUniswapFactory() external view returns (address) {
return uniswapFactory;
}

function submitCurrentDifficulty(uint256 _currentDifficulty) public {
if (currentDifficulty != _currentDifficulty) {
previousDifficulty = currentDifficulty;
Expand Down
48 changes: 48 additions & 0 deletions implementation/contracts/tokens/TBTC.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
pragma solidity 0.4.25;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract TBTC is ERC20Detailed, ERC20 {
/// @dev Constructor, calls ERC20Detailed constructor to set Token info
/// ERC20Detailed(TokenName, TokenSymbol, NumberOfDecimals)
constructor() ERC20Detailed("Trustless bitcoin", "TBTC", 18) public {
// solium-disable-previous-line no-empty-blocks
}

/// @dev Mints an amount of the token and assigns it to an account.
/// Uses the internal _mint function
/// @param _account The account that will receive the created tokens.
/// @param _amount The amount of tokens that will be created.
function mint(address _account, uint256 _amount) public returns (bool){
// NOTE: this is a public function with unchecked minting.
// TODO: enforce calling authority.
_mint(_account, _amount);
return true;
}

/// @dev Burns an amount of the token of a given account
/// deducting from the sender's allowance for said account.
/// Uses the internal _burn function.
/// @param _account The account whose tokens will be burnt.
/// @param _amount The amount of tokens that will be burnt.
function burnFrom(address _account, uint256 _amount) public {
// NOTE: this uses internal function _burn instead of _burnFrom.
// This will bypass allowance check for now.
// TODO: enforce calling authority.
_burn(_account, _amount);
}

/// @dev Transfer tokens from one address to another
/// Uses the internal _transfer function.
/// @param _from The address to send tokens from
/// @param _to The address to transfer tokens to
/// @param _value The amount of tokens to be transferred
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
// NOTE: this overrides transferFrom in openZeppelin ERC20.sol
// in order to bypass allowance check for now.
// TODO: enforce calling authority.
_transfer(_from, _to, _value);
return true;
}
}
Loading