Skip to content

Commit f6de067

Browse files
initial commit
0 parents  commit f6de067

29 files changed

+9253
-0
lines changed

.circleci/config.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: 2
2+
jobs:
3+
build:
4+
docker:
5+
- image: circleci/node:10
6+
steps:
7+
- checkout
8+
9+
- restore_cache:
10+
keys:
11+
- v1-dependencies-{{ checksum "package.json" }}
12+
- v1-dependencies-
13+
14+
- run: yarn
15+
16+
- save_cache:
17+
key: v1-dependencies-{{ checksum "package.json" }}
18+
paths:
19+
- node_modules
20+
21+
- run: yarn prettier:check
22+
23+
- run: yarn compile
24+
25+
- run: yarn test

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.sol linguist-language=Solidity

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build/
2+
node_modules/

.mocharc.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extension": ["ts"],
3+
"spec": "./test/**/*.spec.ts",
4+
"require": "ts-node/register"
5+
}

.prettierrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true,
4+
"printWidth": 120
5+
}

LICENSE

+674
Large diffs are not rendered by default.

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Uniswap v2 Smart Contracts
2+
[![CircleCI](https://circleci.com/gh/Uniswap/uniswap-v2-oracle-example.svg?style=svg)](https://circleci.com/gh/Uniswap/uniswap-v2-oracle-example)
3+
4+
## Local Development
5+
6+
The following assumes the use of `node@^10`.
7+
8+
### Clone Repository
9+
```
10+
git clone https://github.com/Uniswap/uniswap-v2-oracle-example.git
11+
cd uniswap-v2-oracle-example
12+
```
13+
14+
### Install Dependencies
15+
```
16+
yarn
17+
```
18+
19+
### Compile Contracts and Run Tests
20+
```
21+
yarn compile
22+
yarn test
23+
```

contracts/UniswapV2OracleExample.sol

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
pragma solidity 0.5.13;
2+
3+
import "./interfaces/IUniswapV2OracleExample.sol";
4+
import "./interfaces/IUniswapV2Factory.sol";
5+
import "./interfaces/IUniswapV2.sol";
6+
import "./libraries/SafeMath.sol";
7+
import "./libraries/Math.sol";
8+
import "./libraries/UQ128x128.sol";
9+
10+
contract UniswapV2OracleExample is IUniswapV2OracleExample {
11+
using SafeMath for uint;
12+
using UQ128x128 for uint;
13+
14+
address public exchangeAddress;
15+
16+
uint private priceCumulative0;
17+
uint private priceCumulative1;
18+
uint64 private priceCumulative0Overflow;
19+
uint64 private priceCumulative1Overflow;
20+
uint64 private blockNumber;
21+
uint64 private blockTimestamp;
22+
23+
uint public price0;
24+
uint public price1;
25+
uint constant public period = 24 hours;
26+
27+
constructor(address factory, address tokenA, address tokenB) public {
28+
exchangeAddress = IUniswapV2Factory(factory).getExchange(tokenA, tokenB);
29+
}
30+
31+
function quote0(uint128 amount0) public view returns (uint amount1) {
32+
amount1 = UQ128x128.decode(price1.qmul(amount0));
33+
}
34+
35+
function quote1(uint128 amount1) public view returns (uint amount0) {
36+
amount0 = UQ128x128.decode(price0.qmul(amount1));
37+
}
38+
39+
function initialize() public {
40+
require(blockNumber == 0, "UniswapV2Oracle: ALREADY_INITIALIZED");
41+
IUniswapV2 uniswap = IUniswapV2(exchangeAddress);
42+
if (block.number > uniswap.blockNumber()) uniswap.sync();
43+
priceCumulative0 = uniswap.priceCumulative0();
44+
priceCumulative1 = uniswap.priceCumulative1();
45+
priceCumulative0Overflow = uniswap.priceCumulative0Overflow();
46+
priceCumulative1Overflow = uniswap.priceCumulative1Overflow();
47+
blockNumber = uint64(block.number);
48+
// don't set blockTimestamp so that the first call to update sets the price without time discounting
49+
}
50+
51+
function update() public {
52+
require(blockNumber != 0, "UniswapV2Oracle: NOT_INITIALIZED");
53+
IUniswapV2 uniswap = IUniswapV2(exchangeAddress);
54+
if (block.number > uniswap.blockNumber()) uniswap.sync();
55+
uint priceCumulative0New = uniswap.priceCumulative0();
56+
uint priceCumulative0NewOverflow = uniswap.priceCumulative0Overflow();
57+
uint priceCumulative1New = uniswap.priceCumulative1();
58+
uint priceCumulative1NewOverflow = uniswap.priceCumulative1Overflow();
59+
(uint priceCumulative0Delta, uint priceCumulative0DeltaOverflow) = Math.sub512(
60+
priceCumulative0New,
61+
priceCumulative0NewOverflow,
62+
priceCumulative0,
63+
priceCumulative0Overflow
64+
);
65+
(uint priceCumulative1Delta, uint priceCumulative1DeltaOverflow) = Math.sub512(
66+
priceCumulative1New,
67+
priceCumulative1NewOverflow,
68+
priceCumulative1,
69+
priceCumulative1Overflow
70+
);
71+
// fail on overflow
72+
require(priceCumulative0DeltaOverflow == 0 && priceCumulative1DeltaOverflow == 0, "UniswapV2Oracle: OVERFLOW");
73+
uint blocksElapsed = block.number - blockNumber;
74+
uint price0New = priceCumulative0Delta / blocksElapsed;
75+
uint price1New = priceCumulative1Delta / blocksElapsed;
76+
uint secondsElapsed = block.timestamp - blockTimestamp; // solium-disable-line security/no-block-members
77+
if (secondsElapsed < period) {
78+
price0 = (price0.mul(period.sub(secondsElapsed)).add(price0New.mul(secondsElapsed))) / period;
79+
price1 = (price1.mul(period.sub(secondsElapsed)).add(price1New.mul(secondsElapsed))) / period;
80+
} else {
81+
price0 = price0New;
82+
price1 = price1New;
83+
}
84+
priceCumulative0 = priceCumulative0New;
85+
priceCumulative1 = priceCumulative1New;
86+
priceCumulative0Overflow = uint64(priceCumulative0NewOverflow);
87+
priceCumulative1Overflow = uint64(priceCumulative1NewOverflow);
88+
blockNumber = uint64(block.number);
89+
blockTimestamp = uint64(block.timestamp); // solium-disable-line security/no-block-members
90+
}
91+
}

contracts/interfaces/IUniswapV2.sol

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
pragma solidity 0.5.13;
2+
3+
interface IUniswapV2 {
4+
event LiquidityMinted(
5+
address indexed sender,
6+
address indexed recipient,
7+
uint amount0,
8+
uint amount1,
9+
uint128 reserve0,
10+
uint128 reserve1,
11+
uint liquidity
12+
);
13+
event LiquidityBurned(
14+
address indexed sender,
15+
address indexed recipient,
16+
uint amount0,
17+
uint amount1,
18+
uint128 reserve0,
19+
uint128 reserve1,
20+
uint liquidity
21+
);
22+
event Swap(
23+
address indexed sender,
24+
address indexed recipient,
25+
uint amount0,
26+
uint amount1,
27+
uint128 reserve0,
28+
uint128 reserve1,
29+
address input
30+
);
31+
32+
function factory() external view returns (address);
33+
function token0() external view returns (address);
34+
function token1() external view returns (address);
35+
36+
function reserve0() external view returns (uint128);
37+
function reserve1() external view returns (uint128);
38+
function priceCumulative0() external view returns (uint);
39+
function priceCumulative1() external view returns (uint);
40+
function priceCumulative0Overflow() external view returns (uint64);
41+
function priceCumulative1Overflow() external view returns (uint64);
42+
function blockNumber() external view returns (uint64);
43+
44+
function getInputPrice(uint inputAmount, uint inputReserve, uint outputReserve) external pure returns (uint);
45+
46+
function mintLiquidity(address recipient) external returns (uint liquidity);
47+
function burnLiquidity(address recipient) external returns (uint amount0, uint amount1);
48+
function swap0(address recipient) external returns (uint amount1);
49+
function swap1(address recipient) external returns (uint amount0);
50+
function sync() external;
51+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
pragma solidity 0.5.13;
2+
3+
interface IUniswapV2Factory {
4+
event ExchangeCreated(address indexed token0, address indexed token1, address exchange, uint256 exchangeNumber);
5+
6+
function exchangeBytecode() external view returns (bytes memory);
7+
8+
function sortTokens(address tokenA, address tokenB) external pure returns (address, address);
9+
function getExchange(address tokenA, address tokenB) external view returns (address);
10+
function getTokens(address exchange) external view returns (address, address);
11+
function exchanges(uint) external view returns (address);
12+
function exchangesCount() external view returns (uint);
13+
14+
function createExchange(address tokenA, address tokenB) external returns (address exchange);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pragma solidity 0.5.13;
2+
3+
interface IUniswapV2OracleExample {
4+
function exchangeAddress() external returns (address);
5+
function price0() external returns (uint);
6+
function price1() external returns (uint);
7+
function period() external returns (uint);
8+
9+
function quote0(uint128 amount0) external view returns (uint amount1);
10+
function quote1(uint128 amount1) external view returns (uint amount0);
11+
12+
function initialize() external;
13+
function update() external;
14+
}

contracts/libraries/Math.sol

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pragma solidity 0.5.13;
2+
3+
library Math {
4+
function sub512(uint x0, uint x1, uint y0, uint y1) internal pure returns (uint z0, uint z1) {
5+
assembly { // solium-disable-line security/no-inline-assembly
6+
z0 := sub(x0, y0)
7+
z1 := sub(sub(x1, y1), lt(x0, y0))
8+
}
9+
}
10+
}

contracts/libraries/SafeMath.sol

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pragma solidity 0.5.13;
2+
3+
library SafeMath {
4+
function add(uint x, uint y) internal pure returns (uint z) {
5+
require((z = x + y) >= x, "ds-math-add-overflow");
6+
}
7+
function sub(uint x, uint y) internal pure returns (uint z) {
8+
require((z = x - y) <= x, "ds-math-sub-underflow");
9+
}
10+
function mul(uint x, uint y) internal pure returns (uint z) {
11+
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
12+
}
13+
}

contracts/libraries/UQ128x128.sol

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pragma solidity 0.5.13;
2+
3+
library UQ128x128 {
4+
uint constant Q128 = 2**128;
5+
6+
function qmul(uint x, uint128 y) internal pure returns (uint z) {
7+
z = x * y;
8+
}
9+
10+
function decode(uint y) internal pure returns (uint128 z) {
11+
return uint128(y / Q128);
12+
}
13+
}

0 commit comments

Comments
 (0)