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

Commit

Permalink
Merge pull request #263 from keep-network/uniswap-deployment
Browse files Browse the repository at this point in the history
This issue breaks away work from #160 into something more deliverable:

- introduces a script to deploy external systems, based on discussions in #270. Uniswap is deployed from a newly-created package at https://github.com/keep-network/uniswap
- updates README with respect to this
- includes Uniswap Solidity interfaces
- separates unit and integration testing into two suites, new circleci flows for this
- includes an E2E test with our TBTCToken of a Uniswap trade
  • Loading branch information
nkuba authored Sep 19, 2019
2 parents c0b1173 + c591014 commit 46a5dfe
Show file tree
Hide file tree
Showing 19 changed files with 367 additions and 18 deletions.
24 changes: 21 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
set -ex
npm install
npm run sol:lint
test_solidity:
unit_test_contracts:
executor: docker-node
steps:
- checkout
Expand All @@ -49,6 +49,23 @@ jobs:
name: Run NPM tests
working_directory: ~/project/implementation/contracts
command: npm install && npm run test
integration_test_contracts:
executor: docker-node
steps:
- checkout
- run: sudo npm install -g [email protected]
- run:
name: Running testrpc
command: ganache-cli
background: true
- run:
name: Deploy Uniswap
working_directory: ~/project/implementation/scripts
command: ./deploy_uniswap.sh
- run:
name: Run NPM tests
working_directory: ~/project/implementation/contracts
command: npm install && npm run integration-test
generate_pngs:
docker:
- image: keepnetwork/texlive:15
Expand Down Expand Up @@ -213,9 +230,10 @@ workflows:
jobs:
- lint_js
- lint_solidity
solidity:
test:
jobs:
- test_solidity
- unit_test_contracts
- integration_test_contracts
docs:
jobs:
- generate_pngs
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ sudo cp docs/latex/tikz-uml.sty /usr/local/texlive/texmf-local/
# Update TeX package tree
sudo texhash
```

2 changes: 1 addition & 1 deletion implementation/.babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"presets": ["es2015", "stage-2", "stage-3"]
"presets": ["es2015", "stage-2", "stage-3"]
}
25 changes: 20 additions & 5 deletions implementation/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
tBTC
====

Contains the on-chain smart contracts and tests.

### Setup

```
```sh
npm install
```

### Compilation
#### Migrating externals

tBTC interacts with external systems deployed on-chain, such as [Uniswap](https://uniswap.exchange).

During development, these must be deployed to your local blockchain (ie. Ganache).

```sh
cd scripts/
./deploy_uniswap.sh
```

### Compilation

```sh
npm run compile
```

## Lint
### Lint

```
```sh
# Show issues
npm run js:lint
npm run sol:lint
Expand All @@ -25,4 +40,4 @@ npm run sol:lint:fix

Eslint errors can be disabled using a comment on the previous line. For example,
to disable linter errors for the 'no-unused-vars' rule:
`// eslint-disable-next-line no-unused-vars`.
`// eslint-disable-next-line no-unused-vars`.
12 changes: 12 additions & 0 deletions implementation/contracts/external/IUniswapExchange.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity 0.5.10;

interface IUniswapExchange {
// Provide Liquidity
function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256);

// Get Prices
function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);

// Trade ETH to ERC20
function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold);
}
9 changes: 9 additions & 0 deletions implementation/contracts/external/IUniswapFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pragma solidity 0.5.10;

interface IUniswapFactory {
// Create Exchange
function createExchange(address token) external returns (address exchange);

// Get Exchange and Token Info
function getExchange(address token) external view returns (address exchange);
}
17 changes: 16 additions & 1 deletion implementation/contracts/system/TBTCSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@ pragma solidity ^0.5.10;
import {ITBTCSystem} from "../interfaces/ITBTCSystem.sol";
import {DepositLog} from "../DepositLog.sol";
import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

contract TBTCSystem is ITBTCSystem, ERC721, DepositLog {
contract TBTCSystem is Ownable, ITBTCSystem, ERC721, DepositLog {

bool _initialized = false;

uint256 currentDifficulty = 1;
uint256 previousDifficulty = 1;
uint256 oraclePrice = 10 ** 12;

address public tbtcUniswapExchange;

function initialize(address _tbtcUniswapExchange) external onlyOwner {
require(!_initialized, "already initialized");
tbtcUniswapExchange = _tbtcUniswapExchange;
_initialized = true;
}

function getTBTCUniswapExchange() external view returns (address) {
return tbtcUniswapExchange;
}

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

Expand Down
2 changes: 1 addition & 1 deletion implementation/contracts/system/TBTCToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ contract TBTCToken is ERC20Detailed, ERC20, MinterAuthority {
/// @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 onlyDeposit returns (bool) {
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.
Expand Down
6 changes: 1 addition & 5 deletions implementation/migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const TBTCSystem = artifacts.require('TBTCSystem')
// keep
const KeepBridge = artifacts.require('KeepBridge')
const TBTCToken = artifacts.require('TBTCToken')
const KeepRegistryAddress = '0x21dB9E2A9fFa5B5019D55D1a7e7DFD16c116a800' // KeepRegistry contract address

// deposit factory
const DepositFactory = artifacts.require('DepositFactory')
Expand Down Expand Up @@ -85,13 +84,10 @@ module.exports = (deployer, network, accounts) => {

// system
await deployer.deploy(TBTCSystem)

await deployer.deploy(TBTCToken, TBTCSystem.address)

// keep
await deployer.deploy(KeepBridge).then((instance) => {
instance.initialize(KeepRegistryAddress)
})
await deployer.deploy(KeepBridge)

// deposit factory
await deployer.deploy(DepositFactory, Deposit.address)
Expand Down
31 changes: 31 additions & 0 deletions implementation/migrations/3_initialize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const TBTCToken = artifacts.require('TBTCToken')
const IUniswapFactory = artifacts.require('IUniswapFactory')
const KeepBridge = artifacts.require('KeepBridge')
const TBTCSystem = artifacts.require('TBTCSystem')

const {
KeepRegistryAddress,
UniswapFactoryAddress,
} = require('./externals')

module.exports = async function(deployer) {
// Don't enact this setup during unit testing.
if (process.env.NODE_ENV == 'test' && !process.env.INTEGRATION_TEST) return

// Keep
const keepBridge = await KeepBridge.deployed()
await keepBridge.initialize(KeepRegistryAddress)

// Uniswap
const tbtcToken = await TBTCToken.deployed()
const uniswapFactory = await IUniswapFactory.at(UniswapFactoryAddress)

let tbtcExchangeAddress = await uniswapFactory.getExchange(tbtcToken.address)
if (tbtcExchangeAddress == '0x0000000000000000000000000000000000000000') {
await uniswapFactory.createExchange(tbtcToken.address)
tbtcExchangeAddress = await uniswapFactory.getExchange(tbtcToken.address)
}

const tbtcSystem = await TBTCSystem.deployed()
await tbtcSystem.initialize(tbtcExchangeAddress)
}
8 changes: 8 additions & 0 deletions implementation/migrations/externals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Configuration for addresses of externally deployed smart contracts
const KeepRegistryAddress = '0x622B525445aD939f1b0fF1193E57DC0ED75dAb6e'
const UniswapFactoryAddress = '0x1304C8c4233E7b68Cb51b0DDEE33Da9A6dbD0A4A'

module.exports = {
KeepRegistryAddress,
UniswapFactoryAddress,
}
4 changes: 3 additions & 1 deletion implementation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"scripts": {
"clean": "rm -rf build/",
"compile": "truffle compile",
"test": "truffle test",
"test": "NODE_ENV=test truffle test",
"integration-test": "NODE_ENV=test INTEGRATION_TEST=true truffle test",
"test:debug": "NODE_ENV=test node --inspect node_modules/.bin/truffle test",
"js:lint": "eslint ${npm_package_config_eslintPaths}",
"js:lint:fix": "eslint --fix ${npm_package_config_eslintPaths}",
"sol:lint": "solium -d contracts/",
Expand Down
39 changes: 39 additions & 0 deletions implementation/scripts/deploy_uniswap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

SED="sed"

if [[ "$OSTYPE" == "darwin"* ]]; then
if ! [ -x "$(command -v gsed)" ]; then
# See also: https://unix.stackexchange.com/questions/13711/differences-between-sed-on-mac-osx-and-other-standard-sed
echo 'Error: gsed is not installed.' >&2
echo 'GNU sed is required due to difference in functionality from OSX/FreeBSD sed.'
echo 'Install with: brew install gnu-sed'
exit 1
fi
SED="gsed"
fi


# Clone Uniswap for deployment
if [ ! -d uniswap ]; then
git clone https://github.com/keep-network/uniswap
fi

# Setup repo
cd uniswap
git checkout v0.1.0
npm i
export ETH_RPC_URL="http://localhost:8545"

# Run migration
UNISWAP_DEPLOYMENT=$(npm run migrate)

# Get address of UniswapFactory
FACTORY=$(echo "$UNISWAP_DEPLOYMENT" | sed -n /Factory/p | cut -d' ' -f2)

# Update UniswapFactoryAddress in migration
$SED -i -e "/UniswapFactoryAddress/s/0x[a-fA-F0-9]\{0,40\}/$FACTORY/" ../../migrations/externals.js

# Clean up
cd ..
rm -rf uniswap/
3 changes: 2 additions & 1 deletion implementation/test/helpers/expectThrow.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ export default async (promise, expectedErrorMessage) => {
// testrpc log actually show an 'invalid jump' event.)
const outOfGas = error.message.search('out of gas') >= 0
const revert = error.message.search('revert') >= 0
const invalidJump = error.message.search('invalid JUMP')
assert(
invalidOpcode || outOfGas || revert,
invalidOpcode || outOfGas || revert || invalidJump,
'Expected throw, got \'' + error + '\' instead',
)

Expand Down
Loading

0 comments on commit 46a5dfe

Please sign in to comment.