Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
takassh committed Mar 13, 2022
0 parents commit c8cc1cc
Show file tree
Hide file tree
Showing 39 changed files with 62,492 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
artifacts
cache
coverage
31 changes: 31 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = {
settings: {
node: {
allowModules: ["electron"],
resolvePaths: [__dirname],
tryExtensions: [".js", ".json", ".node", ".ts", ".d.ts"],
},
},
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
plugins: ["@typescript-eslint"],
extends: [
"standard",
"plugin:prettier/recommended",
"plugin:node/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
},
rules: {
"node/no-unsupported-features/es-syntax": [
"error",
{ ignores: ["modules"] },
],
},
};
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
.env
coverage
coverage.json
typechain

#Hardhat files
cache
artifacts
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hardhat.config.ts
scripts
test
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
artifacts
cache
coverage*
gasReporterOutput.json
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
7 changes: 7 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", { "ignoreConstructors": true }]
}
}
1 change: 1 addition & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"solidity.compileUsingRemoteVersion": "v0.8.10+commit.fc410830"
}
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Advanced Sample Hardhat Project

This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem.

The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code.

Try running some of the following tasks:

```shell
npx hardhat accounts
npx hardhat compile
npx hardhat clean
npx hardhat test
npx hardhat node
npx hardhat help
REPORT_GAS=true npx hardhat test
npx hardhat coverage
npx hardhat run scripts/deploy.ts
TS_NODE_FILES=true npx ts-node scripts/deploy.ts
npx eslint '**/*.{js,ts}'
npx eslint '**/*.{js,ts}' --fix
npx prettier '**/*.{json,sol,md}' --check
npx prettier '**/*.{json,sol,md}' --write
npx solhint 'contracts/**/*.sol'
npx solhint 'contracts/**/*.sol' --fix
```

# Etherscan verification

To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Ropsten.

In this project, copy the .env.example file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Ropsten node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract:

```shell
hardhat run --network ropsten scripts/deploy.ts
```

Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command:

```shell
npx hardhat verify --network ropsten DEPLOYED_CONTRACT_ADDRESS "Hello, Hardhat!"
```

# Performance optimizations

For faster runs of your tests and scripts, consider skipping ts-node's type checking by setting the environment variable `TS_NODE_TRANSPILE_ONLY` to `1` in hardhat's environment. For more details see [the documentation](https://hardhat.org/guides/typescript.html#performance-optimizations).
82 changes: 82 additions & 0 deletions contracts/FlashLoan.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
pragma abicoder v2;

import "./interfaces/DydxFlashloanBase.sol";
import "./interfaces/ICallee.sol";

contract FlashLoan is ICallee, DydxFlashloanBase {
//main 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e
address private constant SOLO = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;

// JUST FOR TESTING - ITS OKAY TO REMOVE ALL OF THESE VARS
address public flashUser;

event Log(string message, uint val);

struct MyCustomData {
address token;
uint repayAmount;
}

function initiateFlashLoan(address _token, uint _amount) external {
ISoloMargin solo = ISoloMargin(SOLO);

// Get marketId from token address
/*
0 WETH
1 SAI
2 USDC
3 DAI
*/
uint marketId = _getMarketIdFromTokenAddress(SOLO, _token);

// Calculate repay amount (_amount + (2 wei))
uint repayAmount = _getRepaymentAmountInternal(_amount);
IERC20(_token).approve(SOLO, repayAmount);

/*
1. Withdraw
2. Call callFunction()
3. Deposit back
*/

Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);

operations[0] = _getWithdrawAction(marketId, _amount);
operations[1] = _getCallAction(
abi.encode(MyCustomData({token: _token, repayAmount: repayAmount}))
);
operations[2] = _getDepositAction(marketId, repayAmount);

Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();

solo.operate(accountInfos, operations);
}

function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public override {
require(msg.sender == SOLO, "!solo");
require(sender == address(this), "!this contract");

MyCustomData memory mcd = abi.decode(data, (MyCustomData));
uint repayAmount = mcd.repayAmount;

uint bal = IERC20(mcd.token).balanceOf(address(this));
require(bal >= repayAmount, "bal < repay");

// More code here...
flashUser = sender;
emit Log("bal", bal);
emit Log("repay", repayAmount);
emit Log("bal - repay", bal - repayAmount);
}
}
// Solo margin contract mainnet - 0x1e0447b19bb6ecfdae1e4ae1694b0c3659614e4e
// payable proxy - 0xa8b39829cE2246f89B31C013b8Cde15506Fb9A76

// https://etherscan.io/tx/0xda79adea5cdd8cb069feb43952ea0fc510e4b6df4a270edc8130d8118d19e3f4
117 changes: 117 additions & 0 deletions contracts/FlashLoanArbitrage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
pragma abicoder v2;

import "./interfaces/DydxFlashloanBase.sol";
import "./interfaces/ICallee.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";

contract FlashLoanArbitrage is ICallee, DydxFlashloanBase {
//main net
address private constant SOLO = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
address private constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

IUniswapV2Router02 public swapRouter1;
IUniswapV2Router02 public swapRouter2;

struct MyCustomData {
address token;
uint256 repayAmount;
}

function initiateFlashLoan(
address _token,
uint256 _amount,
address _swapRouter1,
address _swapRouter2
) external {
ISoloMargin solo = ISoloMargin(SOLO);

swapRouter1 = IUniswapV2Router02(_swapRouter1);
swapRouter2 = IUniswapV2Router02(_swapRouter2);

// Get marketId from token address
/*
0 WETH
1 SAI
2 USDC
3 DAI
*/
uint256 marketId = _getMarketIdFromTokenAddress(SOLO, _token);

// Calculate repay amount (_amount + (2 wei))
uint256 repayAmount = _getRepaymentAmountInternal(_amount);
IERC20(_token).approve(SOLO, repayAmount);

/*
1. Withdraw
2. Call callFunction()
3. Deposit back
*/

Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);

operations[0] = _getWithdrawAction(marketId, _amount);
operations[1] = _getCallAction(
abi.encode(MyCustomData({token: _token, repayAmount: repayAmount}))
);
operations[2] = _getDepositAction(marketId, repayAmount);

Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();

solo.operate(accountInfos, operations);
}

function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public override {
require(msg.sender == SOLO, "!solo");
require(sender == address(this), "!this contract");

MyCustomData memory mcd = abi.decode(data, (MyCustomData));
uint256 repayAmount = mcd.repayAmount;

uint256 bal = IERC20(mcd.token).balanceOf(address(this));
require(bal >= repayAmount, "bal < repay");

uint256 amountOut = swapExactInputSingle(bal, mcd.token, DAI, true);
swapExactInputSingle(amountOut, DAI, mcd.token, false);

IERC20(mcd.token).transfer(msg.sender, bal - repayAmount);

uint256 profit = IERC20(mcd.token).balanceOf(address(this));
require(profit >= repayAmount, "profit < repay");
}

function swapExactInputSingle(
uint256 amountIn,
address from,
address to,
bool first
) private returns (uint256 amountOut) {
TransferHelper.safeApprove(
from,
address(first ? swapRouter1 : swapRouter2),
amountIn
);

address[] memory path = new address[](2);
path[0] = from;
path[1] = to;

uint256[] memory amountOuts = (first ? swapRouter1 : swapRouter2)
.swapExactTokensForTokens(
amountIn,
0,
path,
msg.sender,
block.timestamp
);

amountOut = amountOuts[0];
}
}
Loading

0 comments on commit c8cc1cc

Please sign in to comment.