Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ deployments
.article.md
contracts/stablecoins/README.md

yarn-error.log
3 changes: 1 addition & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ package.json
img
.env
.*
README.md
coverage.json
deployments
deployments
16 changes: 15 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
{
"tabWidth": 4,
"trailingComma": "es5",
"useTabs": false,
"semi": false,
"singleQuote": false,
"printWidth": 100
"printWidth": 100,
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false,
"explicitTypes": "always"
}
}
]
}

9 changes: 9 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp

// List of extensions which should be recommended for users of this workspace.
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "NomicFoundation.hardhat-solidity"],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"editor.formatOnSave": true,
"solidity.formatter": "prettier", // This is the default so it might be missing.
"[solidity]": {
"editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
},
"eslint.enable": true,
"eslint.validate": ["javascript", "typescript"],
"eslint.alwaysShowStatus": true
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This repo is dedicated to making minimal repos of existing defi primatives.
- `Staking.sol`: Based off [Synthetix](https://synthetix.io/)
- `RewardToken.sol`: Based off [Synthetix](https://synthetix.io/)
- `Exchange.sol` , `Factory.sol` , `Token.sol` : Based off [Uniswap v1](https://docs.uniswap.org/protocol/V1/introduction). The used pricing formula is documented [here](./docs/uniswap-v1/)
- Uniswap-v2: [core and periphery](./docs/uniswap-v2/)
- `DecentralizedStableCoin`: Based off DAI
- `CentralizedStableCoin`: Based off USDC

Expand Down
58 changes: 58 additions & 0 deletions contracts/amm/uniswap-v2/core/UniswapV2ERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.7;

import "./interfaces/IUniswapV2ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract UniswapV2ERC20 is IUniswapV2ERC20, ERC20 {
error EXPIRED(uint256 deadline, uint256 blockTimestamp);
error InvalidSignature(address recoveredAddress, address owner);
bytes32 public override DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant override PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public override nonces;

constructor() ERC20("Uniswap V2", "UNI-V2") {
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes("Uniswap V2")),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}

function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
if (deadline < block.timestamp) revert EXPIRED(deadline, block.timestamp);
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)
)
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
if (recoveredAddress == address(0) || recoveredAddress != owner)
revert InvalidSignature(recoveredAddress, owner);
_approve(owner, spender, value);
}
}
60 changes: 60 additions & 0 deletions contracts/amm/uniswap-v2/core/UniswapV2Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.7;

import "./interfaces/IUniswapV2Factory.sol";
import "./UniswapV2Pair.sol";

contract UniswapV2Factory is IUniswapV2Factory {
error IdenticalAddresses();
error PairExists();
error ZeroAddress();
error Forbidden(address feeTo, address feeToSetter);

address public override feeTo;
address public override feeToSetter;

mapping(address => mapping(address => address)) public override getPair;
address[] public override allPairs;

constructor(address _feeToSetter) {
feeToSetter = _feeToSetter;
}

function allPairsLength() external view override returns (uint256) {
return allPairs.length;
}

function createPair(address tokenA, address tokenB) external override returns (address pair) {
if (tokenA == tokenB) revert IdenticalAddresses();

(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);

if (token0 == address(0)) revert ZeroAddress();

if (getPair[token0][token1] != address(0)) revert PairExists();

bytes memory bytecode = type(UniswapV2Pair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}

IUniswapV2Pair(pair).initialize(token0, token1);

getPair[token0][token1] = pair;
getPair[token1][token0] = pair;
allPairs.push(pair);

emit PairCreated(token0, token1, pair, allPairs.length);
}

function setFeeTo(address _feeTo) external override {
if (msg.sender != feeToSetter) revert Forbidden(msg.sender, feeToSetter);
feeTo = _feeTo;
}

function setFeeToSetter(address _feeToSetter) external override {
if (msg.sender != feeToSetter) revert Forbidden(msg.sender, feeToSetter);
feeToSetter = _feeToSetter;
}
}
Loading