Merge branch 'feat/uniswap-staker' of https://github.com/Instadapp/dsa-connectors into feat/uniswap-staker

This commit is contained in:
cryptoDev222 2021-09-07 14:36:34 -05:00
commit 9142035f1f
42 changed files with 2153 additions and 493 deletions

View File

@ -9,18 +9,40 @@ jobs:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v1
with:
# Checkout the head ref instead of the PR branch that github creates.
ref: ${{ github.head_ref }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install and build
run: |
npm install
- name: Run status checks
run: node ./status-checks
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Use Cache
uses: actions/cache@v2
with:
path: |
node_modules
*/*/node_modules
key: ${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('**/package-lock.json') }}
- name: Install and build
run: |
npm install
- name: Run status checks
id: status_check
run: |
output=$(node ./status-checks)
# Escape newlines so _all_ the output is included in the set-output
output="${output//'%'/'%25'}"
output="${output//$'\n'/'%0A'}"
output="${output//$'\r'/'%0D'}"
echo "::set-output name=status_check_output::$output"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Auto Comment Status Check Result
# Use with caution
uses: bubkoo/auto-comment@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pullRequestSynchronize: "${{ steps.status_check.outputs.status_check_output }}"
pullRequestAssigned: "${{ steps.status_check.outputs.status_check_output }}"
pullRequestOpened: "${{ steps.status_check.outputs.status_check_output }}"
pullRequestReopened: "${{ steps.status_check.outputs.status_check_output }}"

412
README.md
View File

@ -4,391 +4,53 @@ Connectors are standard proxy logics contract that let DeFi Smart Account (DSA)
DSAs are powerful because they can easily be extended with connectors. Every new connector that is added is immediately usable by any developer building on top of DSAs. Connectors can either be base connectors to protocols, auth connectors, higher level connectors with more specific use cases like optimized lending, or connectors to native liquidity pools.
You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained [here](docs/how-to-add-new-connector.md). Following is the list of all the supported connectors. Following is the list of all the primary connectors used to cast spells:
You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained below.
[Read this post to learn about getId and setId used in the connectors](https://discuss.instadapp.io/t/how-to-use-getid-setid/104)
List of all the mainnet connector for referrence is [here](https://github.com/Instadapp/dsa-connectors/tree/main/contracts/mainnet/connectors)
## Authority
## How to add a new connector
[Code](contracts/mainnet/connectors/authority/main.sol)
You can create a new PR to add a new connector. To get the PR merged, certain requirements needs to be met which will be explained here.
### `add(authority)`
### New connector should follow the current directory structure
**Add an address authority**
Common files for all connectors are in `contracts/common` directory.
`authority` - Address of the authority to add
* `math.sol` has methods for mathematical operations (`DSMath`)
* `interfaces.sol` contains the common interfaces
* `TokenInterface` for ERC-20 interface including WETH
* `stores.sol` contains the global constants as well as methods `getId` & `setId` (`Stores`)
* `basic.sol` inherits `DSMath` & `Stores` contracts. This contains few details explained below
* Wrapping & unwrapping ETH (`convertEthToWeth` & `convertWethToEth`)
* Getting token & ETH balance of DSA
### `remove(authority)`
Connectors are under `contracts/connectors` directory, and should be formatted as follows:
**Remove an address authority**
* Connector events should be in a separate contract: `events.sol`
* Interfaces should be defined in a seperate file: `interface.sol`
* If the connector has helper methods & constants (including interface instances), this should be defined in a separate file: `helpers.sol`
* `Helpers` contract should inherit `Basic` contract from common directory
* If the connector doesn't have any helper methods, the main contract should inherit `Basic` contract
* The main logic of the contract should be under `main.sol`, and the contract should inherit `Helpers` (if exists, otherwise `Basic`) & `Events`
`authority` - Address of the authority to remove
Few things to consider while writing the connector:
## Basic
* Connector should have a public constant string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1`
* Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound`
* User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables:
* `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)`
* `_eventParam` of `bytes` type: This will be the abi encoded event parameters
* The contracts should not have `selfdestruct()`
* The contracts should not have `delegatecall()`
* Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere
* Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20)
* Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc
* Only `approve()` (declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell.
* User interacting functions should have natspec comments(@dev, @notice, @param).
* Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell
* Use `setUint()` (declared in `Stores`) for setting value to save for the future spell
[Code](contracts/mainnet/connectors/basic/main.sol)
### Support
### `deposit(erc20, amt, getId, setId)`
If you can't find something you're looking for or have any questions, ask them at our developers community on [Discord](https://discord.gg/83vvrnY) or simply send an [Email](mailto:info@instadapp.io).
**Deposit a token or ETH to DSA.**
`erc20` - Address of the token to deposit. ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
`amt` - Amount of token to deposit
In case of an ERC20 Token, allowance must be given to DSA before depositing
### `withdraw(erc20, amt, getId, setId)`
**Withdraw a token or ETH from DSA.**
`erc20` - Address of the token to withdraw. ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
`amt` - Amount of token to withdraw
`to` - Address to which token will be withdrawn
## MakerDAO
[Code](contracts/mainnet/connectors/makerdao/main.sol)
### `open(collateralType)`
**Open a Maker vault** of the `collateralType`. E.g. "ETH-A", "USDC-B", etc...
### `close(vault)`
**Close a Maker vault**
`vault` - Vault ID (Use 0 for last opened vault)
### `deposit(vault, amt, getId, setId)`
**Deposit collateral to a Maker vault.**
`vault` - Vault ID (Use 0 for last opened vault)
`amt` - Amount of collteral to deposit
### `withdraw(vault, amt, getId, setId)`
**Withdraw collateral from a Maker vault.**
`vault` - Vault ID (Use 0 for last opened vault)
`amt` - Amount of collteral to withdraw
### `borrow(vault, amt, getId, setId)`
**Borrow DAI from a Maker vault.**
`vault` - Vault ID (Use 0 for last opened vault)
`amt` - Amount of DAI to borrow
### `payback(vault, amt, getId, setId)`
**Payback DAI to a Maker vault.**
`vault` - Vault ID (Use 0 for last opened vault)
`amt` - Amount of DAI to payback
### `withdrawLiquidated(vault, amt, getId, setId)`
**Withdraw leftover collateral after liquidation.**
`vault` - Vault ID (Use 0 for last opened vault)
`amt` - Amount of collateral to withdraw
### `depositAndBorrow(vault, depositAmt, borrowAmt, getIdDeposit, getIdBorrow, setIdDeposit, setIdBorrow)`
**Deposit collateral & borrow DAI from a vault.**
`vault` - Vault ID (Use 0 for last opened vault)
`depositAmt` - Amount of collateral to deposit
`borrowAmt` - Amount of DAI to borrow
## Compound
[Code](contracts/mainnet/connectors/compound/main.sol)
### `deposit(token, amt, getId, setId)`
**Deposit token to Compound.**
`token` - Address of the token to deposit
`amt` - Amount of token to deposit
### `withdraw(token, amt, getId, setId)`
**Withdraw token from Compound.**
`token` - Address of the token to withdraw
`amt` - Amount of token to withdraw
### `borrow(token, amt, getId, setId)`
**Borrow token from Compound.**
`token` - Address of the token to borrow
`amt` - Amount of token to borrow
### `payback(token, amt, getId, setId)`
**Payback debt to Compound.**
`token` - Address of the token to payback
`amt` - Amount of token to payback
## COMP
[Code](contracts/mainnet/connectors/COMP/main.sol)
### `ClaimComp(setId)`
**Claim unclaimed COMP**
### `ClaimCompTwo(tokens, setId)`
**Claim unclaimed COMP**
`tokens` - List of tokens supplied or borrowed
### `ClaimCompThree(supplyTokens, borrowTokens, setId)`
**Claim unclaimed COMP**
`supplyTokens` - List of tokens supplied
`borrowTokens` - List of tokens borrowed
### `delegate(delegatee)`
**Delegate COMP votes**
`delegatee` - Address of the delegatee
## Aave v1
[Code](contracts/mainnet/connectors/aave/main.sol)
### `deposit(token, amt, getId, setId)`
**Deposit token to Aave.**
`token` - Address of the token to deposit
`amt` - Amount of token to deposit
### `withdraw(token, amt, getId, setId)`
**Withdraw token from Aave.**
`token` - Address of the token to withdraw
`amt` - Amount of token to withdraw
### `borrow(token, amt, getId, setId)`
**Borrow token from Aave.**
`token` - Address of the token to borrow
`amt` - Amount of token to borrow
### `payback(token, amt, getId, setId)`
**Payback debt to Aave.**
`token` - Address of the token to payback
`amt` - Amount of token to payback
## Aave v2
[Code](contracts/mainnet/connectors/aave_v2/main.sol)
### `deposit(token, amt, getId, setId)`
**Deposit token to Aave.**
`token` - Address of the token to deposit
`amt` - Amount of token to deposit
### `withdraw(token, amt, getId, setId)`
**Withdraw token from Aave.**
`token` - Address of the token to withdraw
`amt` - Amount of token to withdraw
### `borrow(token, amt, rateMode, getId, setId)`
**Borrow token from Aave.**
`token` - Address of the token to borrow
`amt` - Amount of token to borrow
`rateMode` - Borrow interest rate mode (1 = Stable & 2 = Variable)
### `payback(token, amt, rateMode, getId, setId)`
**Payback debt to Aave.**
`token` - Address of the token to payback
`amt` - Amount of token to payback
`rateMode` - Borrow interest rate mode (1 = Stable & 2 = Variable)
## dYdX
[Code](contracts/mainnet/connectors/dydx/main.sol)
### `deposit(token, amt, getId, setId)`
**Deposit token to dYdX.**
`token` - Address of the token to deposit
`amt` - Amount of token to deposit
### `withdraw(token, amt, getId, setId)`
**Withdraw token from dYdX.**
`token` - Address of the token to withdraw
`amt` - Amount of token to withdraw
### `borrow(token, amt, getId, setId)`
**Borrow token from dYdX.**
`token` - Address of the token to borrow
`amt` - Amount of token to borrow
### `payback(token, amt, getId, setId)`
**Payback debt to dYdX.**
`token` - Address of the token to payback
`amt` - Amount of token to payback
## Uniswap
[Code](contracts/mainnet/connectors/uniswap/main.sol)
### `deposit(tokenA, tokenB, amtA, unitAmt, slippage, getId, setId)`
**Deposit liquidity to tokenA/tokenB pool**
`tokenA` - Address of token A
`tokenB` - Address of token B
`amtA` - Amount of token A to deposit
`unitAmt` - Unit amount of amtB/amtA with slippage.
`slippage` - Slippage amount in wei
### `withdraw(tokenA, tokenB, uniAmt, unitAmtA, unitAmtB, getId, setId)`
**Withdraw liquidity from tokenA/tokenB pool**
`tokenA` - Address of token A
`tokenB` - Address of token B
`uniAmt` - Amount of LP tokens to withdraw
`unitAmtA` - Unit amount of amtA/uniAmt with slippage.
`unitAmtB` - Unit amount of amtB/uniAmt with slippage.
### `buy(buyAddr, sellAddr, buyAmt, unitAmt, getId, setId)`
**Buy a token/ETH**
`buyAddr` - Address of the buying token
`sellAddr` - Address of the selling token
`buyAmt` - Amount of tokens to buy
`unitAmt` - Unit amount of sellAmt/buyAmt with slippage
### `sell(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)`
**Sell a token/ETH**
`buyAddr` - Address of the buying token
`sellAddr` - Address of the selling token
`sellAmt` - Amount of tokens to sell
`unitAmt` - Unit amount of buyAmt/sellAmt with slippage
## 1Inch
[Code](contracts/mainnet/connectors/1inch/main.sol)
### `sell(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)`
**Sell ETH/ERC20 using 1proto**
`buyAddr` - Address of the buying token
`sellAddr` - Address of the selling token
`sellAmt` - Amount of tokens to sell
`unitAmt` - Unit amount of buyAmt/sellAmt with slippage
### `sellTwo(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)`
**Sell ETH/ERC20 using 1proto**
`buyAddr` - Address of the buying token
`sellAddr` - Address of the selling token
`sellAmt` - Amount of tokens to sell
`unitAmt` - Unit amount of buyAmt/sellAmt with slippage
`[]distribution` - Distribution of swap across different dex.
`disableDexes` - Disable a dex. (To disable none: 0)
### `sellTwo(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)`
**Sell ETH/ERC20 using 1inch**
Use [1Inch API](https://docs.1inch.exchange/api/) for calldata
`buyAddr` - Address of the buying token
`sellAddr` - Address of the selling token
`sellAmt` - Amount of tokens to sell
`unitAmt` - Unit amount of buyAmt/sellAmt with slippage
`callData` - Data from 1inch API

View File

@ -19,7 +19,7 @@ abstract contract Helpers is DSMath, Basic {
/**
* @dev Compound Mapping
*/
CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082);
CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88);
function getMergedCTokens(
string[] calldata supplyIds,

View File

@ -99,5 +99,5 @@ abstract contract CompResolver is Events, Helpers {
}
contract ConnectV2COMP is CompResolver {
string public constant name = "COMP-v1";
string public constant name = "COMP-v1.1";
}

View File

@ -0,0 +1,62 @@
pragma solidity ^0.7.0;
contract Events {
event LogDeposit(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
event LogWithdraw(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
event LogBorrow(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
event LogPayback(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
event LogDepositCToken(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 cTokenAmt,
uint256 getId,
uint256 setId
);
event LogWithdrawCToken(
address indexed token,
address cToken,
uint256 tokenAmt,
uint256 cTokenAmt,
uint256 getId,
uint256 setId
);
event LogLiquidate(
address indexed borrower,
address indexed tokenToPay,
address indexed tokenInReturn,
uint256 tokenAmt,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,26 @@
pragma solidity ^0.7.0;
import { DSMath } from "./../../../common/math.sol";
import { Basic } from "./../../../common/basic.sol";
import { ComptrollerInterface, CompoundMappingInterface, BComptrollerInterface } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev Compound Comptroller
*/
ComptrollerInterface internal constant troller = ComptrollerInterface(0x9dB10B9429989cC13408d7368644D4A1CB704ea3);
/**
* @dev Compound Mapping
*/
CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88);
/**
* @dev B.Compound Mapping
*/
function getMapping(string calldata tokenId) public returns(address token, address btoken) {
address ctoken;
(token, ctoken) = compMapping.getMapping(tokenId);
btoken = BComptrollerInterface(address(troller)).c2b(ctoken);
}
}

View File

@ -0,0 +1,40 @@
pragma solidity ^0.7.0;
interface CTokenInterface {
function mint(uint mintAmount) external returns (uint);
function redeem(uint redeemTokens) external returns (uint);
function borrow(uint borrowAmount) external returns (uint);
function repayBorrow(uint repayAmount) external returns (uint);
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ERC20
function liquidateBorrow(address borrower, uint repayAmount, address cTokenCollateral) external returns (uint);
function borrowBalanceCurrent(address account) external returns (uint);
function redeemUnderlying(uint redeemAmount) external returns (uint);
function exchangeRateCurrent() external returns (uint);
function balanceOf(address owner) external view returns (uint256 balance);
}
interface CETHInterface {
function mint() external payable;
function repayBorrow() external payable;
function repayBorrowBehalf(address borrower) external payable;
function liquidateBorrow(address borrower, address cTokenCollateral) external payable;
}
interface ComptrollerInterface {
function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
function exitMarket(address cTokenAddress) external returns (uint);
function getAssetsIn(address account) external view returns (address[] memory);
function getAccountLiquidity(address account) external view returns (uint, uint, uint);
function claimComp(address) external;
}
interface CompoundMappingInterface {
function cTokenMapping(string calldata tokenId) external view returns (address);
function getMapping(string calldata tokenId) external view returns (address, address);
}
interface BComptrollerInterface {
function c2b(address ctoken) external view returns(address);
}

View File

@ -0,0 +1,347 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/**
* @title B.Compound.
* @dev Lending & Borrowing.
*/
import { TokenInterface } from "../../../common/interfaces.sol";
import { Stores } from "../../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { CETHInterface, CTokenInterface } from "./interface.sol";
abstract contract BCompoundResolver is Events, Helpers {
/**
* @dev Deposit ETH/ERC20_Token.
* @notice Deposit a token to Compound for lending / collaterization.
* @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposited.
*/
function depositRaw(
address token,
address cToken,
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
if (token == ethAddr) {
_amt = _amt == uint(-1) ? address(this).balance : _amt;
CETHInterface(cToken).mint{value: _amt}();
} else {
TokenInterface tokenContract = TokenInterface(token);
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
approve(tokenContract, cToken, _amt);
require(CTokenInterface(cToken).mint(_amt) == 0, "deposit-failed");
}
setUint(setId, _amt);
_eventName = "LogDeposit(address,address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, _amt, getId, setId);
}
/**
* @dev Deposit ETH/ERC20_Token using the Mapping.
* @notice Deposit a token to Compound for lending / collaterization.
* @param tokenId The token id of the token to deposit.(For eg: ETH-A)
* @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposited.
*/
function deposit(
string calldata tokenId,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = depositRaw(token, cToken, amt, getId, setId);
}
/**
* @dev Withdraw ETH/ERC20_Token.
* @notice Withdraw deposited token from Compound
* @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param amt The amount of the token to withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens withdrawn.
*/
function withdrawRaw(
address token,
address cToken,
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
CTokenInterface cTokenContract = CTokenInterface(cToken);
if (_amt == uint(-1)) {
TokenInterface tokenContract = TokenInterface(token);
uint initialBal = token == ethAddr ? address(this).balance : tokenContract.balanceOf(address(this));
require(cTokenContract.redeem(cTokenContract.balanceOf(address(this))) == 0, "full-withdraw-failed");
uint finalBal = token == ethAddr ? address(this).balance : tokenContract.balanceOf(address(this));
_amt = finalBal - initialBal;
} else {
require(cTokenContract.redeemUnderlying(_amt) == 0, "withdraw-failed");
}
setUint(setId, _amt);
_eventName = "LogWithdraw(address,address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, _amt, getId, setId);
}
/**
* @dev Withdraw ETH/ERC20_Token using the Mapping.
* @notice Withdraw deposited token from Compound
* @param tokenId The token id of the token to withdraw.(For eg: ETH-A)
* @param amt The amount of the token to withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens withdrawn.
*/
function withdraw(
string calldata tokenId,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = withdrawRaw(token, cToken, amt, getId, setId);
}
/**
* @dev Borrow ETH/ERC20_Token.
* @notice Borrow a token using Compound
* @param token The address of the token to borrow. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param amt The amount of the token to borrow.
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens borrowed.
*/
function borrowRaw(
address token,
address cToken,
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
require(CTokenInterface(cToken).borrow(_amt) == 0, "borrow-failed");
setUint(setId, _amt);
_eventName = "LogBorrow(address,address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, _amt, getId, setId);
}
/**
* @dev Borrow ETH/ERC20_Token using the Mapping.
* @notice Borrow a token using Compound
* @param tokenId The token id of the token to borrow.(For eg: DAI-A)
* @param amt The amount of the token to borrow.
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens borrowed.
*/
function borrow(
string calldata tokenId,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = borrowRaw(token, cToken, amt, getId, setId);
}
/**
* @dev Payback borrowed ETH/ERC20_Token.
* @notice Payback debt owed.
* @param token The address of the token to payback. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param amt The amount of the token to payback. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens paid back.
*/
function paybackRaw(
address token,
address cToken,
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
CTokenInterface cTokenContract = CTokenInterface(cToken);
_amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(address(this)) : _amt;
if (token == ethAddr) {
require(address(this).balance >= _amt, "not-enough-eth");
CETHInterface(cToken).repayBorrow{value: _amt}();
} else {
TokenInterface tokenContract = TokenInterface(token);
require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token");
approve(tokenContract, cToken, _amt);
require(cTokenContract.repayBorrow(_amt) == 0, "repay-failed.");
}
setUint(setId, _amt);
_eventName = "LogPayback(address,address,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, _amt, getId, setId);
}
/**
* @dev Payback borrowed ETH/ERC20_Token using the Mapping.
* @notice Payback debt owed.
* @param tokenId The token id of the token to payback.(For eg: COMP-A)
* @param amt The amount of the token to payback. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens paid back.
*/
function payback(
string calldata tokenId,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = paybackRaw(token, cToken, amt, getId, setId);
}
/**
* @dev Deposit ETH/ERC20_Token.
* @notice Same as depositRaw. The only difference is this method stores cToken amount in set ID.
* @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of cTokens received.
*/
function depositCTokenRaw(
address token,
address cToken,
uint256 amt,
uint256 getId,
uint256 setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
CTokenInterface ctokenContract = CTokenInterface(cToken);
uint initialBal = ctokenContract.balanceOf(address(this));
if (token == ethAddr) {
_amt = _amt == uint(-1) ? address(this).balance : _amt;
CETHInterface(cToken).mint{value: _amt}();
} else {
TokenInterface tokenContract = TokenInterface(token);
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
approve(tokenContract, cToken, _amt);
require(ctokenContract.mint(_amt) == 0, "deposit-ctoken-failed.");
}
uint _cAmt;
{
uint finalBal = ctokenContract.balanceOf(address(this));
_cAmt = sub(finalBal, initialBal);
setUint(setId, _cAmt);
}
_eventName = "LogDepositCToken(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, _amt, _cAmt, getId, setId);
}
/**
* @dev Deposit ETH/ERC20_Token using the Mapping.
* @notice Same as deposit. The only difference is this method stores cToken amount in set ID.
* @param tokenId The token id of the token to depositCToken.(For eg: DAI-A)
* @param amt The amount of the token to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of cTokens received.
*/
function depositCToken(
string calldata tokenId,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = depositCTokenRaw(token, cToken, amt, getId, setId);
}
/**
* @dev Withdraw CETH/CERC20_Token using cToken Amt.
* @notice Same as withdrawRaw. The only difference is this method fetch cToken amount in get ID.
* @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param cToken The address of the corresponding cToken.
* @param cTokenAmt The amount of cTokens to withdraw
* @param getId ID to retrieve cTokenAmt
* @param setId ID stores the amount of tokens withdrawn.
*/
function withdrawCTokenRaw(
address token,
address cToken,
uint cTokenAmt,
uint getId,
uint setId
) public payable returns (string memory _eventName, bytes memory _eventParam) {
uint _cAmt = getUint(getId, cTokenAmt);
require(token != address(0) && cToken != address(0), "invalid token/ctoken address");
CTokenInterface cTokenContract = CTokenInterface(cToken);
TokenInterface tokenContract = TokenInterface(token);
_cAmt = _cAmt == uint(-1) ? cTokenContract.balanceOf(address(this)) : _cAmt;
uint withdrawAmt;
{
uint initialBal = token != ethAddr ? tokenContract.balanceOf(address(this)) : address(this).balance;
require(cTokenContract.redeem(_cAmt) == 0, "redeem-failed");
uint finalBal = token != ethAddr ? tokenContract.balanceOf(address(this)) : address(this).balance;
withdrawAmt = sub(finalBal, initialBal);
}
setUint(setId, withdrawAmt);
_eventName = "LogWithdrawCToken(address,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(token, cToken, withdrawAmt, _cAmt, getId, setId);
}
/**
* @dev Withdraw CETH/CERC20_Token using cToken Amt & the Mapping.
* @notice Same as withdraw. The only difference is this method fetch cToken amount in get ID.
* @param tokenId The token id of the token to withdraw CToken.(For eg: ETH-A)
* @param cTokenAmt The amount of cTokens to withdraw
* @param getId ID to retrieve cTokenAmt
* @param setId ID stores the amount of tokens withdrawn.
*/
function withdrawCToken(
string calldata tokenId,
uint cTokenAmt,
uint getId,
uint setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
(address token, address cToken) = getMapping(tokenId);
(_eventName, _eventParam) = withdrawCTokenRaw(token, cToken, cTokenAmt, getId, setId);
}
}
contract ConnectV2BCompound is BCompoundResolver {
string public name = "B.Compound-v1.0";
}

View File

@ -0,0 +1,22 @@
pragma solidity ^0.7.6;
contract Events {
/* Stability Pool */
event LogStabilityDeposit(
address indexed borrower,
uint amount,
uint lqtyGain,
uint getDepositId,
uint setDepositId,
uint setLqtyGainId
);
event LogStabilityWithdraw(
address indexed borrower,
uint numShares,
uint lqtyGain,
uint getWithdrawId,
uint setWithdrawId,
uint setLqtyGainId
);
}

View File

@ -0,0 +1,18 @@
pragma solidity ^0.7.6;
import { DSMath } from "../../../common/math.sol";
import { Basic } from "../../../common/basic.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
import {
StabilityPoolLike,
BAMMLike
} from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
StabilityPoolLike internal constant stabilityPool = StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb);
TokenInterface internal constant lqtyToken = TokenInterface(0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D);
TokenInterface internal constant lusdToken = TokenInterface(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0);
BAMMLike internal constant BAMM = BAMMLike(0x0d3AbAA7E088C2c82f54B2f47613DA438ea8C598);
}

View File

@ -0,0 +1,17 @@
pragma solidity ^0.7.6;
interface StabilityPoolLike {
function provideToSP(uint _amount, address _frontEndTag) external;
function withdrawFromSP(uint _amount) external;
function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;
function getDepositorETHGain(address _depositor) external view returns (uint);
function getDepositorLQTYGain(address _depositor) external view returns (uint);
function getCompoundedLUSDDeposit(address _depositor) external view returns (uint);
}
interface BAMMLike {
function deposit(uint lusdAmount) external;
function withdraw(uint numShares) external;
function balanceOf(address a) external view returns(uint);
function totalSupply() external view returns(uint);
}

View File

@ -0,0 +1,86 @@
pragma solidity ^0.7.6;
/**
* @title B.Liquity.
* @dev Lending & Borrowing.
*/
import {
StabilityPoolLike,
BAMMLike
} from "./interface.sol";
import { Stores } from "../../../common/stores.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
abstract contract BLiquityResolver is Events, Helpers {
/* Begin: Stability Pool */
/**
* @dev Deposit LUSD into Stability Pool
* @notice Deposit LUSD into Stability Pool
* @param amount Amount of LUSD to deposit into Stability Pool
* @param getDepositId Optional storage slot to retrieve the amount of LUSD from
* @param setDepositId Optional storage slot to store the final amount of LUSD deposited
* @param setLqtyGainId Optional storage slot to store any LQTY gains in
*/
function deposit(
uint amount,
uint getDepositId,
uint setDepositId,
uint setLqtyGainId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
amount = getUint(getDepositId, amount);
amount = amount == uint(-1) ? lusdToken.balanceOf(address(this)) : amount;
uint lqtyBalanceBefore = lqtyToken.balanceOf(address(this));
lusdToken.approve(address(BAMM), amount);
BAMM.deposit(amount);
uint lqtyBalanceAfter = lqtyToken.balanceOf(address(this));
uint lqtyGain = sub(lqtyBalanceAfter, lqtyBalanceBefore);
setUint(setDepositId, amount);
setUint(setLqtyGainId, lqtyGain);
_eventName = "LogStabilityDeposit(address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(address(this), amount,lqtyGain, getDepositId, setDepositId, setLqtyGainId);
}
/**
* @dev Withdraw user deposited LUSD from Stability Pool
* @notice Withdraw LUSD from Stability Pool
* @param numShares amount of shares to withdraw from the BAMM
* @param getWithdrawId Optional storage slot to retrieve the amount of LUSD to withdraw from
* @param setWithdrawId Optional storage slot to store the withdrawn LUSD
* @param setLqtyGainId Optional storage slot to store any LQTY gains in
*/
function withdraw(
uint numShares,
uint getWithdrawId,
uint setWithdrawId,
uint setLqtyGainId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
numShares = getUint(getWithdrawId, numShares);
numShares = numShares == uint(-1) ? BAMM.balanceOf(address(this)) : numShares;
uint lqtyBalanceBefore = lqtyToken.balanceOf(address(this));
BAMM.withdraw(numShares);
uint lqtyBalanceAfter = lqtyToken.balanceOf(address(this));
uint lqtyGain = sub(lqtyBalanceAfter, lqtyBalanceBefore);
setUint(setWithdrawId, numShares);
setUint(setLqtyGainId, lqtyGain);
_eventName = "LogStabilityWithdraw(address,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(address(this), numShares, lqtyGain, getWithdrawId, setWithdrawId, setLqtyGainId);
}
}
contract ConnectV2BLiquity is BLiquityResolver {
string public name = "B.Liquity-v1";
}

View File

@ -0,0 +1,26 @@
pragma solidity ^0.7.0;
contract Events {
event LogOpen(uint256 indexed vault, bytes32 indexed ilk);
event LogClose(uint256 indexed vault, bytes32 indexed ilk);
event LogTransfer(uint256 indexed vault, bytes32 indexed ilk, address newOwner);
event LogDeposit(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdraw(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogBorrow(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogPayback(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdrawLiquidated(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogExitDai(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId);
event LogDepositDai(uint256 tokenAmt, uint256 getId, uint256 setId);
event LogWithdrawDai(uint256 tokenAmt, uint256 getId, uint256 setId);
event LogDepositAndBorrow(
uint256 indexed vault,
bytes32 indexed ilk,
uint256 depositAmt,
uint256 borrowAmt,
uint256 getIdDeposit,
uint256 getIdBorrow,
uint256 setIdDeposit,
uint256 setIdBorrow
);
}

View File

@ -0,0 +1,130 @@
pragma solidity ^0.7.0;
import { DSMath } from "../../../common/math.sol";
import { Basic } from "../../../common/basic.sol";
import { TokenInterface } from "./../../../common/interfaces.sol";
import { BManagerLike, DaiJoinInterface, PotLike, VatLike, JugLike } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {
/**
* @dev Manager Interface
*/
BManagerLike internal constant managerContract = BManagerLike(0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed);
/**
* @dev DAI Join
*/
DaiJoinInterface internal constant daiJoinContract = DaiJoinInterface(0x9759A6Ac90977b93B58547b4A71c78317f391A28);
/**
* @dev Pot
*/
PotLike internal constant potContract = PotLike(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7);
/**
* @dev Maker MCD Jug Address.
*/
JugLike internal constant mcdJug = JugLike(0x19c0976f590D67707E62397C87829d896Dc0f1F1);
/**
* @dev Return Close Vault Address.
*/
address internal constant giveAddr = 0x4dD58550eb15190a5B3DfAE28BB14EeC181fC267;
/**
* @dev Get Vault's ilk.
*/
function getVaultData(uint vault) internal view returns (bytes32 ilk, address urn) {
ilk = managerContract.ilks(vault);
urn = managerContract.urns(vault);
}
/**
* @dev Gem Join address is ETH type collateral.
*/
function isEth(address tknAddr) internal pure returns (bool) {
return tknAddr == wethAddr ? true : false;
}
/**
* @dev Get Vault Debt Amount.
*/
function _getVaultDebt(
address vat,
bytes32 ilk,
address urn,
uint vault
) internal view returns (uint wad) {
(, uint rate,,,) = VatLike(vat).ilks(ilk);
(, uint art) = VatLike(vat).urns(ilk, urn);
uint cushion = managerContract.cushion(vault);
art = add(art, cushion);
uint dai = VatLike(vat).dai(urn);
uint rad = sub(mul(art, rate), dai);
wad = rad / RAY;
wad = mul(wad, RAY) < rad ? wad + 1 : wad;
}
/**
* @dev Get Borrow Amount.
*/
function _getBorrowAmt(
address vat,
address urn,
bytes32 ilk,
uint amt
) internal returns (int dart)
{
uint rate = mcdJug.drip(ilk);
uint dai = VatLike(vat).dai(urn);
if (dai < mul(amt, RAY)) {
dart = toInt(sub(mul(amt, RAY), dai) / rate);
dart = mul(uint(dart), rate) < mul(amt, RAY) ? dart + 1 : dart;
}
}
/**
* @dev Get Payback Amount.
*/
function _getWipeAmt(
address vat,
uint amt,
address urn,
bytes32 ilk,
uint vault
) internal view returns (int dart)
{
(, uint rate,,,) = VatLike(vat).ilks(ilk);
(, uint art) = VatLike(vat).urns(ilk, urn);
uint cushion = managerContract.cushion(vault);
art = add(art, cushion);
dart = toInt(amt / rate);
dart = uint(dart) <= art ? - dart : - toInt(art);
}
/**
* @dev Convert String to bytes32.
*/
function stringToBytes32(string memory str) internal pure returns (bytes32 result) {
require(bytes(str).length != 0, "string-empty");
// solium-disable-next-line security/no-inline-assembly
assembly {
result := mload(add(str, 32))
}
}
/**
* @dev Get vault ID. If `vault` is 0, get last opened vault.
*/
function getVault(uint vault) internal view returns (uint _vault) {
if (vault == 0) {
require(managerContract.count(address(this)) > 0, "no-vault-opened");
_vault = managerContract.last(address(this));
} else {
_vault = vault;
}
}
}

View File

@ -0,0 +1,66 @@
pragma solidity ^0.7.0;
import { TokenInterface } from "../../../common/interfaces.sol";
interface ManagerLike {
function cdpCan(address, uint, address) external view returns (uint);
function ilks(uint) external view returns (bytes32);
function last(address) external view returns (uint);
function count(address) external view returns (uint);
function owns(uint) external view returns (address);
function urns(uint) external view returns (address);
function vat() external view returns (address);
function open(bytes32, address) external returns (uint);
function give(uint, address) external;
function frob(uint, int, int) external;
function flux(uint, address, uint) external;
function move(uint, address, uint) external;
}
interface BManagerLike is ManagerLike {
function cushion(uint) external view returns (uint);
function cdpi() external view returns (uint);
}
interface VatLike {
function can(address, address) external view returns (uint);
function ilks(bytes32) external view returns (uint, uint, uint, uint, uint);
function dai(address) external view returns (uint);
function urns(bytes32, address) external view returns (uint, uint);
function frob(
bytes32,
address,
address,
address,
int,
int
) external;
function hope(address) external;
function move(address, address, uint) external;
function gem(bytes32, address) external view returns (uint);
}
interface TokenJoinInterface {
function dec() external returns (uint);
function gem() external returns (TokenInterface);
function join(address, uint) external payable;
function exit(address, uint) external;
}
interface DaiJoinInterface {
function vat() external returns (VatLike);
function dai() external returns (TokenInterface);
function join(address, uint) external payable;
function exit(address, uint) external;
}
interface JugLike {
function drip(bytes32) external returns (uint);
}
interface PotLike {
function pie(address) external view returns (uint);
function drip() external returns (uint);
function join(uint) external;
function exit(uint) external;
}

View File

@ -0,0 +1,521 @@
pragma solidity ^0.7.0;
/**
* @title MakerDAO.
* @dev Collateralized Borrowing.
*/
import { TokenInterface, AccountInterface } from "./../../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { VatLike, TokenJoinInterface } from "./interface.sol";
abstract contract BMakerResolver is Helpers, Events {
/**
* @dev Open Vault
* @notice Open a MakerDAO Vault
* @param colType Type of Collateral.(eg: 'ETH-A')
*/
function open(string calldata colType) external payable returns (string memory _eventName, bytes memory _eventParam) {
bytes32 ilk = stringToBytes32(colType);
require(instaMapping.gemJoinMapping(ilk) != address(0), "wrong-col-type");
uint256 vault = managerContract.open(ilk, address(this));
_eventName = "LogOpen(uint256,bytes32)";
_eventParam = abi.encode(vault, ilk);
}
/**
* @dev Close Vault
* @notice Close a MakerDAO Vault
* @param vault Vault ID to close.
*/
function close(uint256 vault) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
(uint ink, uint art) = VatLike(managerContract.vat()).urns(ilk, urn);
require(ink == 0 && art == 0, "vault-has-assets");
require(managerContract.owns(_vault) == address(this), "not-owner");
managerContract.give(_vault, giveAddr);
_eventName = "LogClose(uint256,bytes32)";
_eventParam = abi.encode(_vault, ilk);
}
/**
* @dev Transfer Vault
* @notice Transfer a MakerDAO Vault to "nextOwner"
* @param vault Vault ID to close.
* @param nextOwner Address of the next owner of the vault.
*/
function transfer(
uint vault,
address nextOwner
) external payable returns (string memory _eventName, bytes memory _eventParam) {
require(AccountInterface(address(this)).isAuth(nextOwner), "nextOwner-is-not-auth");
uint256 _vault = getVault(vault);
(bytes32 ilk,) = getVaultData(_vault);
require(managerContract.owns(_vault) == address(this), "not-owner");
managerContract.give(_vault, nextOwner);
_eventName = "LogTransfer(uint256,bytes32,address)";
_eventParam = abi.encode(_vault, ilk, nextOwner);
}
/**
* @dev Deposit ETH/ERC20_Token Collateral.
* @notice Deposit collateral to a MakerDAO vault
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt The amount of tokens to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposited.
*/
function deposit(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
address colAddr = instaMapping.gemJoinMapping(ilk);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
TokenInterface tokenContract = tokenJoinContract.gem();
if (isEth(address(tokenContract))) {
_amt = _amt == uint(-1) ? address(this).balance : _amt;
tokenContract.deposit{value: _amt}();
} else {
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
}
approve(tokenContract, address(colAddr), _amt);
tokenJoinContract.join(urn, _amt);
managerContract.frob(
_vault,
toInt(convertTo18(tokenJoinContract.dec(), _amt)),
0
);
setUint(setId, _amt);
_eventName = "LogDeposit(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_vault, ilk, _amt, getId, setId);
}
/**
* @dev Withdraw ETH/ERC20_Token Collateral.
* @notice Withdraw collateral from a MakerDAO vault
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt The amount of tokens to withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens withdrawn.
*/
function withdraw(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
address colAddr = instaMapping.gemJoinMapping(ilk);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
uint _amt18;
if (_amt == uint(-1)) {
(_amt18,) = VatLike(managerContract.vat()).urns(ilk, urn);
_amt = convert18ToDec(tokenJoinContract.dec(), _amt18);
} else {
_amt18 = convertTo18(tokenJoinContract.dec(), _amt);
}
managerContract.frob(
_vault,
-toInt(_amt18),
0
);
managerContract.flux(
_vault,
address(this),
_amt18
);
TokenInterface tokenContract = tokenJoinContract.gem();
if (isEth(address(tokenContract))) {
tokenJoinContract.exit(address(this), _amt);
tokenContract.withdraw(_amt);
} else {
tokenJoinContract.exit(address(this), _amt);
}
setUint(setId, _amt);
_eventName = "LogWithdraw(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_vault, ilk, _amt, getId, setId);
}
/**
* @dev Borrow DAI.
* @notice Borrow DAI using a MakerDAO vault
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt The amount of DAI to borrow.
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of DAI borrowed.
*/
function borrow(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
VatLike vatContract = VatLike(managerContract.vat());
managerContract.frob(
_vault,
0,
_getBorrowAmt(
address(vatContract),
urn,
ilk,
_amt
)
);
managerContract.move(
_vault,
address(this),
toRad(_amt)
);
if (vatContract.can(address(this), address(daiJoinContract)) == 0) {
vatContract.hope(address(daiJoinContract));
}
daiJoinContract.exit(address(this), _amt);
setUint(setId, _amt);
_eventName = "LogBorrow(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_vault, ilk, _amt, getId, setId);
}
/**
* @dev Payback borrowed DAI.
* @notice Payback DAI debt owed by a MakerDAO vault
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt The amount of DAI to payback. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of DAI paid back.
*/
function payback(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
address vat = managerContract.vat();
uint _maxDebt = _getVaultDebt(vat, ilk, urn, vault);
_amt = _amt == uint(-1) ? _maxDebt : _amt;
require(_maxDebt >= _amt, "paying-excess-debt");
approve(daiJoinContract.dai(), address(daiJoinContract), _amt);
daiJoinContract.join(urn, _amt);
managerContract.frob(
_vault,
0,
_getWipeAmt(
vat,
VatLike(vat).dai(urn),
urn,
ilk,
_vault
)
);
setUint(setId, _amt);
_eventName = "LogPayback(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_vault, ilk, _amt, getId, setId);
}
/**
* @dev Withdraw leftover ETH/ERC20_Token after Liquidation.
* @notice Withdraw leftover collateral after Liquidation.
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt token amount to Withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of collateral withdrawn.
*/
function withdrawLiquidated(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
(bytes32 ilk, address urn) = getVaultData(vault);
address colAddr = instaMapping.gemJoinMapping(ilk);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
uint _amt18;
if (_amt == uint(-1)) {
_amt18 = VatLike(managerContract.vat()).gem(ilk, urn);
_amt = convert18ToDec(tokenJoinContract.dec(), _amt18);
} else {
_amt18 = convertTo18(tokenJoinContract.dec(), _amt);
}
managerContract.flux(
vault,
address(this),
_amt18
);
TokenInterface tokenContract = tokenJoinContract.gem();
tokenJoinContract.exit(address(this), _amt);
if (isEth(address(tokenContract))) {
tokenContract.withdraw(_amt);
}
setUint(setId, _amt);
_eventName = "LogWithdrawLiquidated(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(vault, ilk, _amt, getId, setId);
}
struct MakerData {
uint _vault;
address colAddr;
TokenJoinInterface tokenJoinContract;
VatLike vatContract;
TokenInterface tokenContract;
}
/**
* @dev Deposit ETH/ERC20_Token Collateral and Borrow DAI.
* @notice Deposit collateral and borrow DAI.
* @param vault Vault ID. (Use 0 for last opened vault)
* @param depositAmt The amount of tokens to deposit. (For max: `uint256(-1)`)
* @param borrowAmt The amount of DAI to borrow.
* @param getIdDeposit ID to retrieve depositAmt.
* @param getIdBorrow ID to retrieve borrowAmt.
* @param setIdDeposit ID stores the amount of tokens deposited.
* @param setIdBorrow ID stores the amount of DAI borrowed.
*/
function depositAndBorrow(
uint256 vault,
uint256 depositAmt,
uint256 borrowAmt,
uint256 getIdDeposit,
uint256 getIdBorrow,
uint256 setIdDeposit,
uint256 setIdBorrow
) external payable returns (string memory _eventName, bytes memory _eventParam) {
MakerData memory makerData;
uint _amtDeposit = getUint(getIdDeposit, depositAmt);
uint _amtBorrow = getUint(getIdBorrow, borrowAmt);
makerData._vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(makerData._vault);
makerData.colAddr = instaMapping.gemJoinMapping(ilk);
makerData.tokenJoinContract = TokenJoinInterface(makerData.colAddr);
makerData.vatContract = VatLike(managerContract.vat());
makerData.tokenContract = makerData.tokenJoinContract.gem();
if (isEth(address(makerData.tokenContract))) {
_amtDeposit = _amtDeposit == uint(-1) ? address(this).balance : _amtDeposit;
makerData.tokenContract.deposit{value: _amtDeposit}();
} else {
_amtDeposit = _amtDeposit == uint(-1) ? makerData.tokenContract.balanceOf(address(this)) : _amtDeposit;
}
approve(makerData.tokenContract, address(makerData.colAddr), _amtDeposit);
makerData.tokenJoinContract.join(urn, _amtDeposit);
managerContract.frob(
makerData._vault,
toInt(convertTo18(makerData.tokenJoinContract.dec(), _amtDeposit)),
_getBorrowAmt(
address(makerData.vatContract),
urn,
ilk,
_amtBorrow
)
);
managerContract.move(
makerData._vault,
address(this),
toRad(_amtBorrow)
);
if (makerData.vatContract.can(address(this), address(daiJoinContract)) == 0) {
makerData.vatContract.hope(address(daiJoinContract));
}
daiJoinContract.exit(address(this), _amtBorrow);
setUint(setIdDeposit, _amtDeposit);
setUint(setIdBorrow, _amtBorrow);
_eventName = "LogDepositAndBorrow(uint256,bytes32,uint256,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
makerData._vault,
ilk,
_amtDeposit,
_amtBorrow,
getIdDeposit,
getIdBorrow,
setIdDeposit,
setIdBorrow
);
}
/**
* @dev Exit DAI from urn.
* @notice Exit DAI from urn.
* @param vault Vault ID. (Use 0 for last opened vault)
* @param amt The amount of DAI to exit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of DAI exited.
*/
function exitDai(
uint256 vault,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _vault = getVault(vault);
(bytes32 ilk, address urn) = getVaultData(_vault);
VatLike vatContract = VatLike(managerContract.vat());
if(_amt == uint(-1)) {
_amt = vatContract.dai(urn);
_amt = _amt / 10 ** 27;
}
managerContract.move(
_vault,
address(this),
toRad(_amt)
);
if (vatContract.can(address(this), address(daiJoinContract)) == 0) {
vatContract.hope(address(daiJoinContract));
}
daiJoinContract.exit(address(this), _amt);
setUint(setId, _amt);
_eventName = "LogExitDai(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_vault, ilk, _amt, getId, setId);
}
/**
* @dev Deposit DAI in DSR.
* @notice Deposit DAI in DSR.
* @param amt The amount of DAI to deposit. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of DAI deposited.
*/
function depositDai(
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
_amt = _amt == uint(-1) ?
daiJoinContract.dai().balanceOf(address(this)) :
_amt;
VatLike vat = daiJoinContract.vat();
uint chi = potContract.drip();
approve(daiJoinContract.dai(), address(daiJoinContract), _amt);
daiJoinContract.join(address(this), _amt);
if (vat.can(address(this), address(potContract)) == 0) {
vat.hope(address(potContract));
}
potContract.join(mul(_amt, RAY) / chi);
setUint(setId, _amt);
_eventName = "LogDepositDai(uint256,uint256,uint256)";
_eventParam = abi.encode(_amt, getId, setId);
}
/**
* @dev Withdraw DAI from DSR.
* @notice Withdraw DAI from DSR.
* @param amt The amount of DAI to withdraw. (For max: `uint256(-1)`)
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of DAI withdrawn.
*/
function withdrawDai(
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
VatLike vat = daiJoinContract.vat();
uint chi = potContract.drip();
uint pie;
if (_amt == uint(-1)) {
pie = potContract.pie(address(this));
_amt = mul(chi, pie) / RAY;
} else {
pie = mul(_amt, RAY) / chi;
}
potContract.exit(pie);
uint bal = vat.dai(address(this));
if (vat.can(address(this), address(daiJoinContract)) == 0) {
vat.hope(address(daiJoinContract));
}
daiJoinContract.exit(
address(this),
bal >= mul(_amt, RAY) ? _amt : bal / RAY
);
setUint(setId, _amt);
_eventName = "LogWithdrawDai(uint256,uint256,uint256)";
_eventParam = abi.encode(_amt, getId, setId);
}
}
contract ConnectV2BMakerDAO is BMakerResolver {
string public constant name = "B.MakerDAO-v1.0";
}

View File

@ -17,8 +17,8 @@ abstract contract BasicResolver is Events, DSMath, Basic {
/**
* @dev Deposit Assets To Smart Account.
* @notice Deposit a token to DSA
* @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @notice Deposit a token to DSA.
* @param token The address of the token to deposit.<br>(For <b>ETH</b>: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.<br>For <b>ERC20</b>: Need to give allowance prior casting spells.)
* @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for ETH))
* @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposited.

View File

@ -13,7 +13,7 @@ abstract contract Helpers is DSMath, Basic {
/**
* @dev Compound Mapping
*/
CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082);
CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88);
/**
* @dev enter compound market

View File

@ -23,6 +23,7 @@ contract LiquidityResolver is DSMath, Stores, Variables, Events {
* @dev Borrow Flashloan and Cast spells.
* @param token Token Address.
* @param amt Token Amount.
* @param route Flashloan source route. (0: dYdX(ETH,DAI,USDC only), 1: MakerDAO(DAI only), 2: Compound(All borrowable tokens in Compound), 3: AaveV2(All borrowable tokens in AaveV2))
* @param data targets & data for cast.
*/
function flashBorrowAndCast(
@ -74,4 +75,4 @@ contract LiquidityResolver is DSMath, Stores, Variables, Events {
contract ConnectV2InstaPool is LiquidityResolver {
string public name = "Instapool-v1.1";
}
}

View File

@ -29,8 +29,7 @@ abstract contract Helpers is DSMath, Basic {
uint maxFeePercentage;
uint withdrawAmount;
uint depositAmount;
uint borrowAmount;
uint repayAmount;
uint lusdChange;
bool isBorrow;
}

View File

@ -226,7 +226,7 @@ abstract contract LiquityResolver is Events, Helpers {
withdrawAmount = getUint(getIds[1], withdrawAmount);
adjustTrove.withdrawAmount = withdrawAmount == uint(-1) ? troveManager.getTroveColl(address(this)) : withdrawAmount;
adjustTrove.borrowAmount = getUint(getIds[2], borrowAmount);
borrowAmount = getUint(getIds[2], borrowAmount);
repayAmount = getUint(getIds[3], repayAmount);
if (repayAmount == uint(-1)) {
@ -234,14 +234,14 @@ abstract contract LiquityResolver is Events, Helpers {
uint _totalDebt = troveManager.getTroveDebt(address(this));
repayAmount = _lusdBal > _totalDebt ? _totalDebt : _lusdBal;
}
adjustTrove.repayAmount = repayAmount;
adjustTrove.isBorrow = borrowAmount > 0;
adjustTrove.lusdChange = adjustTrove.isBorrow ? borrowAmount : repayAmount;
borrowerOperations.adjustTrove{value: adjustTrove.depositAmount}(
adjustTrove.maxFeePercentage,
adjustTrove.withdrawAmount,
adjustTrove.borrowAmount,
adjustTrove.lusdChange,
adjustTrove.isBorrow,
upperHint,
lowerHint
@ -249,11 +249,11 @@ abstract contract LiquityResolver is Events, Helpers {
setUint(setIds[0], adjustTrove.depositAmount);
setUint(setIds[1], adjustTrove.withdrawAmount);
setUint(setIds[2], adjustTrove.borrowAmount);
setUint(setIds[3], adjustTrove.repayAmount);
setUint(setIds[2], borrowAmount);
setUint(setIds[3], repayAmount);
_eventName = "LogAdjust(address,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[])";
_eventParam = abi.encode(address(this), maxFeePercentage, adjustTrove.depositAmount, adjustTrove.withdrawAmount, adjustTrove.borrowAmount, adjustTrove.repayAmount, getIds, setIds);
_eventParam = abi.encode(address(this), maxFeePercentage, adjustTrove.depositAmount, adjustTrove.withdrawAmount, borrowAmount, repayAmount, getIds, setIds);
}
/**

View File

@ -35,7 +35,7 @@ contract Helpers is Basic {
/**
* @dev Return InstaDApp Mapping Address
*/
address constant internal getMappingAddr = 0xA8F9D4aA7319C54C04404765117ddBf9448E2082; // CompoundMapping Address
address constant internal getMappingAddr = 0xe7a85d0adDB972A4f0A4e57B698B37f171519e88; // CompoundMapping Address
/**
* @dev Return Compound Comptroller Address

View File

@ -335,5 +335,5 @@ contract RefinanceResolver is CompoundHelpers, AaveV1Helpers, AaveV2Helpers {
}
contract ConnectV2Refinance is RefinanceResolver {
string public name = "Refinance-v1.0";
string public name = "Refinance-v1.1";
}

View File

@ -1,8 +1,8 @@
pragma solidity ^0.7.0;
import { TokenInterface } from "../../common/interfaces.sol";
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
import { DSMath } from "../../../common/math.sol";
import { Basic } from "../../../common/basic.sol";
import { IUniswapV2Router02, IUniswapV2Factory } from "./interface.sol";
abstract contract Helpers is DSMath, Basic {

View File

@ -5,7 +5,7 @@ pragma solidity ^0.7.0;
* @dev Decentralized Exchange.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";

View File

@ -1,9 +1,9 @@
pragma solidity ^0.7.6;
pragma abicoder v2;
import {TokenInterface} from "../../common/interfaces.sol";
import {DSMath} from "../../common/math.sol";
import {Basic} from "../../common/basic.sol";
import {TokenInterface} from "../../../common/interfaces.sol";
import {DSMath} from "../../../common/math.sol";
import {Basic} from "../../../common/basic.sol";
import "./interface.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@uniswap/v3-core/contracts/libraries/TickMath.sol";

View File

@ -6,7 +6,7 @@ pragma abicoder v2;
* @dev Decentralized Exchange.
*/
import {TokenInterface} from "../../common/interfaces.sol";
import {TokenInterface} from "../../../common/interfaces.sol";
import {Helpers} from "./helpers.sol";
import {Events} from "./events.sol";

View File

@ -3,22 +3,23 @@ pragma solidity ^0.7.0;
contract Events {
event LogDeposit(uint256 tokenId);
event LogWithdraw(uint256 indexed tokenId, address to);
event LogWithdraw(uint256 indexed tokenId);
event LogDepositTransfer(uint256 indexed tokenId, address to);
event LogStake(uint256 tokenId, address refundee);
event LogStake(uint256 indexed tokenId, bytes32 incentiveId);
event LogUnstake(uint256 tokenId, bytes32 incentiveId);
event LogUnstake(uint256 indexed tokenId, bytes32 incentiveId);
event LogRewardClaimed(
address rewardToken,
address receiver,
address indexed rewardToken,
uint256 amount
);
event LogIncentiveCreated(
bytes32 incentiveId,
address poolAddr,
address refundee,
uint256 startTime,
uint256 endTime,
uint256 reward

View File

@ -1,9 +1,9 @@
pragma solidity ^0.7.6;
pragma abicoder v2;
import {TokenInterface} from "../../common/interfaces.sol";
import {DSMath} from "../../common/math.sol";
import {Basic} from "../../common/basic.sol";
import {TokenInterface} from "../../../common/interfaces.sol";
import {DSMath} from "../../../common/math.sol";
import {Basic} from "../../../common/basic.sol";
import "./interface.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@uniswap/v3-core/contracts/libraries/TickMath.sol";
@ -32,42 +32,6 @@ abstract contract Helpers is DSMath, Basic {
tokenId = nftManager.tokenOfOwnerByIndex(user, len - 1);
}
function getMinAmount(
TokenInterface token,
uint256 amt,
uint256 slippage
) internal view returns (uint256 minAmt) {
uint256 _amt18 = convertTo18(token.decimals(), amt);
minAmt = wmul(_amt18, sub(WAD, slippage));
minAmt = convert18ToDec(token.decimals(), minAmt);
}
function getNftTokenPairAddresses(uint256 _tokenId)
internal
view
returns (address token0, address token1)
{
(bool success, bytes memory data) = address(nftManager).staticcall(
abi.encodeWithSelector(nftManager.positions.selector, _tokenId)
);
require(success, "fetching positions failed");
{
(, , token0, token1, , , , ) = abi.decode(
data,
(
uint96,
address,
address,
address,
uint24,
int24,
int24,
uint128
)
);
}
}
function getPoolAddress(uint256 _tokenId)
internal
view

View File

@ -6,7 +6,7 @@ pragma abicoder v2;
* @dev Decentralized Exchange.
*/
import {TokenInterface} from "../../common/interfaces.sol";
import {TokenInterface} from "../../../common/interfaces.sol";
import "./interface.sol";
import {Helpers} from "./helpers.sol";
import {Events} from "./events.sol";
@ -56,18 +56,17 @@ abstract contract UniswapResolver is Helpers, Events {
* @dev Withdraw NFT LP token
* @notice Withdraw NFT LP token from staking pool
* @param _tokenId NFT LP Token ID
* @param _to address to transfer
*/
function withdraw(uint256 _tokenId, address _to)
function withdraw(uint256 _tokenId)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
if (_tokenId == 0) _tokenId = _getLastNftId(address(this));
staker.withdrawToken(_tokenId, _to, "");
staker.withdrawToken(_tokenId, address(this), "");
_eventName = "LogWithdraw(uint256,address)";
_eventParam = abi.encode(_tokenId, _to);
_eventName = "LogWithdraw(uint256)";
_eventParam = abi.encode(_tokenId);
}
/**
@ -104,8 +103,8 @@ abstract contract UniswapResolver is Helpers, Events {
);
_stake(_tokenId, _key);
_eventName = "LogStake(uint256,address)";
_eventParam = abi.encode(_tokenId, _refundee);
_eventName = "LogStake(uint256,bytes32)";
_eventParam = abi.encode(_tokenId, keccak256(abi.encode(_key)));
}
/**
@ -142,20 +141,18 @@ abstract contract UniswapResolver is Helpers, Events {
);
_unstake(_key, _tokenId);
_eventName = "LogUnstake(uint256,bytes32)";
_eventParam = abi.encode(_tokenId, _key);
_eventParam = abi.encode(_tokenId, keccak256(abi.encode(_key)));
}
/**
* @dev Claim rewards
* @notice Claim rewards
* @param _rewardToken _rewardToken address
* @param _to address to receive
* @param _amountRequested requested amount
* @param _amount requested amount
*/
function claimRewards(
address _rewardToken,
address _to,
uint256 _amountRequested
uint256 _amount
)
external
payable
@ -163,12 +160,12 @@ abstract contract UniswapResolver is Helpers, Events {
{
uint256 rewards = _claimRewards(
IERC20Minimal(_rewardToken),
_to,
_amountRequested
address(this),
_amount
);
_eventName = "LogRewardClaimed(address,address,uint256)";
_eventParam = abi.encode(_rewardToken, _to, rewards);
_eventName = "LogRewardClaimed(address,uint256)";
_eventParam = abi.encode(_rewardToken, rewards);
}
/**
@ -207,8 +204,8 @@ abstract contract UniswapResolver is Helpers, Events {
}
staker.createIncentive(_key, _reward);
_eventName = "LogIncentiveCreated(address,uint256,uint256,uint256)";
_eventParam = abi.encode(_poolAddr, _startTime, _endTime, _reward);
_eventName = "LogIncentiveCreated(bytes32,address,address,uint256,uint256,uint256)";
_eventParam = abi.encode(keccak256(abi.encode(_key)), _poolAddr, _refundee, _startTime, _endTime, _reward);
}
}

View File

@ -5,12 +5,12 @@
"BASIC-A": "0x9926955e0Dd681Dc303370C52f4Ad0a4dd061687",
"1INCH-A": "0x235fca310ac7be45c7ad45f111203468743e4b7c",
"1INCH-B": "0xaBac3dCf164eD827EAfda8e05eCc8208D6bc5E04",
"COMPOUND-A": "0xbb153cf09a123746e0eb3b3a436c544a7eeb24b6",
"COMPOUND-A": "0x1B1EACaa31abbE544117073f6F8F658a56A3aE25",
"AAVE-V1-A": "0x612c5CA43230D9F97a0ac87E4420F66b8DF97e9D",
"AAVE-V2-A": "0x68b27A84101ac5120bBAb7Ce8d6b096C961df52C",
"MAKERDAO-A": "0x4049db23c605b197f764072569b8db2464653ef6",
"UNISWAP-V2-A": "0x1E5CE41BdB653734445FeC3553b61FebDdaFC43c",
"COMP-A": "0xB446e325D44C52b93eC122Bf76301f235f90B9c9",
"COMP-A": "0x907F0C8c99B08606eE0A51ec5Bc3dFdbFC2d92f3",
"UNISWAP-A": "0xA4BF319968986D2352FA1c550D781bBFCCE3FcaB",
"POLYGON-BRIDGE-A": "0x1b79B302132370B434fb7807b36CB72FB0510aD5",
"AAVE-CLAIM-A": "0x611C1FA59Aa1d6352c4C8bD44882063c6aEE85E0",
@ -22,9 +22,14 @@
"INSTAPOOL-A": "0x5806Af7AB22E2916fA582Ff05731Bf7C682387B2",
"MAKERDAO-CLAIM-A": "0x2f8cBE650af98602a215b6482F2aD60893C5A4E8",
"WETH-A": "0x22075fa719eFb02Ca3cF298AFa9C974B7465E5D3",
"REFINANCE-A": "0x9eA34bE6dA51aa9F6408FeA79c946FDCFA424442",
"REFINANCE-A": "0x6f22931423e8ffC8d51f6E5aF73118fC64b27856",
"INST-A": "0x52C2C4a0db049255fF345EB9D3Fb1f555b7a924A",
"REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8"
"REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8",
"LIQUITY-A": "0x3643bA40B8e2bd8F77233BDB6abe38c218f31bFe",
"UNISWAP-V3-A": "0x25B0c76dE86C3457b9B8b9ee3775F5a7b8D4c475",
"B-COMPOUND-A": "0xa3EeFDc2de9DFA59968bEcff3E15b53E6162460f",
"B-MAKERDAO-A": "0xB0A1f10FeEfECf25064CE7cdF0a65042F7dE7bF0",
"B-LIQUITY-A": "0x19574E5Dfb40bbD63A4F3bdcF27ed662b329b2ff"
},
"137" : {
"1INCH-A": "0xC0d9210496afE9763F5d8cEb8deFfBa817232A9e",
@ -37,6 +42,7 @@
},
"mappings": {
"InstaMappingController": "0xDdd075D5e1024901E4038461e1e4BbC3A48a08d4",
"InstaCompoundMapping": "0xe7a85d0adDB972A4f0A4e57B698B37f171519e88",
"InstaReflexerGebMapping": "0x573e5132693C046D1A9F75Bac683889164bA41b4"
}
}

View File

@ -31,7 +31,7 @@ Few things to consider while writing the connector:
* `_eventParam` of `bytes` type: This will be the abi encoded event parameters
* The contracts should not have `selfdestruct()`
* The contracts should not have `delegatecall()`
* Use `uint(-1)` for maximum amount everywhere
* Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere
* Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20)
* Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc
* Only `approve()` limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell.

View File

@ -3,7 +3,7 @@ const { ethers } = hre;
async function main() {
const CONNECTORS_V2 = "0xFE2390DAD597594439f218190fC2De40f9Cf1179";
const CONNECTORS_V2 = "0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11";
const ctokenMapping = {
"ETH-A": "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5",
@ -16,7 +16,13 @@ async function main() {
"USDT-A": "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9",
"WBTC-A": "0xc11b1268c1a384e55c48c2391d8d480264a3a7f4",
"WBTC-B": "0xccF4429DB6322D5C611ee964527D42E5d685DD6a",
"ZRX-A": "0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407"
"ZRX-A": "0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407",
"YFI-A": "0x80a2ae356fc9ef4305676f7a3e2ed04e12c33946",
"SUSHI-A": "0x4b0181102a0112a2ef11abee5563bb4a3176c9d7",
"MKR-A": "0x95b4ef2869ebd94beb4eee400a99824bf5dc325b",
"AAVE-A": "0xe65cdb6479bac1e22340e4e755fae7e509ecd06c",
"TUSD-A": "0x12392f67bdf24fae0af363c24ac620a2f67dad86",
"LINK-A": "0xface851a4921ce59e912d19329929ce6da6eb0c7",
}
const tokenMapping = {
@ -30,7 +36,13 @@ async function main() {
"USDT-A": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"WBTC-A": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"WBTC-B": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"ZRX-A": "0xe41d2489571d322189246dafa5ebde1f4699f498"
"ZRX-A": "0xe41d2489571d322189246dafa5ebde1f4699f498",
"YFI-A": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e",
"SUSHI-A": "0x6B3595068778DD592e39A122f4f5a5cF09C90fE2",
"MKR-A": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2",
"AAVE-A": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
"TUSD-A": "0x0000000000085d4780B73119b644AE5ecd22b376",
"LINK-A": "0x514910771af9ca656af840dff83e8264ecf986ca",
}
const Mapping = await ethers.getContractFactory("InstaCompoundMapping");

View File

@ -0,0 +1,128 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { web3, deployments, waffle, ethers } = hre;
const { provider, deployContract } = waffle
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/buildDSAv2")
const encodeSpells = require("../../scripts/encodeSpells.js")
const getMasterSigner = require("../../scripts/getMasterSigner")
const addresses = require("../../scripts/constant/addresses");
const abis = require("../../scripts/constant/abis");
const constants = require("../../scripts/constant/constant");
const tokens = require("../../scripts/constant/tokens");
const connectV2CompoundArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/compound/main.sol/ConnectV1BCompound.json")
describe("B.Compound", function () {
const connectorName = "B.COMPOUND-TEST-A"
let dsaWallet0
let masterSigner;
let instaConnectorsV2;
let connector;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
masterSigner = await getMasterSigner(wallet3)
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: connectV2CompoundArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
console.log("Connector address", connector.address)
})
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
expect(await connector.name()).to.be.equal("B.Compound-v1.0");
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
});
});
describe("Main", function () {
it("Should deposit ETH in Compound", async function () {
const amount = ethers.utils.parseEther("1") // 1 ETH
const spells = [
{
connector: connectorName,
method: "deposit",
args: ["ETH-A", amount, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("9"));
});
it("Should borrow and payback DAI from Compound", async function () {
const amount = ethers.utils.parseEther("100") // 100 DAI
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "borrow",
args: ["DAI-A", amount, 0, setId]
},
{
connector: connectorName,
method: "payback",
args: ["DAI-A", 0, setId, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("9"));
});
it("Should deposit all ETH in Compound", async function () {
const spells = [
{
connector: connectorName,
method: "deposit",
args: ["ETH-A", constants.max_value, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("0"));
});
it("Should withdraw all ETH from Compound", async function () {
const spells = [
{
connector: connectorName,
method: "withdraw",
args: ["ETH-A", constants.max_value, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
});
})
})

View File

@ -0,0 +1,181 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { web3, deployments, waffle, ethers } = hre;
const { provider, deployContract } = waffle
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/buildDSAv2")
const encodeSpells = require("../../scripts/encodeSpells.js")
const getMasterSigner = require("../../scripts/getMasterSigner")
const addresses = require("../../scripts/constant/addresses");
const abis = require("../../scripts/constant/abis");
const constants = require("../../scripts/constant/constant");
const tokens = require("../../scripts/constant/tokens");
const connectorLiquityArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/liquity/main.sol/ConnectV2BLiquity.json")
const LUSD_WHALE = "0x66017D22b0f8556afDd19FC67041899Eb65a21bb" // stability pool
const BAMM_ADDRESS = "0x0d3AbAA7E088C2c82f54B2f47613DA438ea8C598"
describe("B.Liquity", function () {
const connectorName = "B.LIQUITY-TEST-A"
let dsaWallet0;
let dsaWallet1;
let masterSigner;
let instaConnectorsV2;
let connector;
let manager;
let vat;
let lusd;
let bammToken;
let stabilityPool;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
masterSigner = await getMasterSigner(wallet3)
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: connectorLiquityArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
lusd = await ethers.getContractAt("../artifacts/contracts/mainnet/common/interfaces.sol:TokenInterface", "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0")
bammToken = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/liquity/interface.sol:BAMMLike", BAMM_ADDRESS)
stabilityPool = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/liquity/interface.sol:StabilityPoolLike", "0x66017D22b0f8556afDd19FC67041899Eb65a21bb")
console.log("Connector address", connector.address)
})
it("test veryClose.", async function () {
expect(veryClose(1000001, 1000000)).to.be.true
expect(veryClose(1000000, 1000001)).to.be.true
expect(veryClose(1003000, 1000001)).to.be.false
expect(veryClose(1000001, 1000300)).to.be.false
});
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
expect(await connector.name()).to.be.equal("B.Liquity-v1");
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
dsaWallet1 = await buildDSAv2(wallet1.address)
expect(!!dsaWallet1.address).to.be.true;
});
it("Deposit LUSD into DSA wallet", async function () {
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [LUSD_WHALE],
});
const signer = await hre.ethers.provider.getSigner(LUSD_WHALE);
await lusd.connect(signer).transfer(dsaWallet0.address, ethers.utils.parseEther("100000"))
expect(await lusd.balanceOf(dsaWallet0.address)).to.equal(ethers.utils.parseEther("100000"));
});
});
describe("Main", function () {
it("should deposit 10k LUSD", async function () {
const totalSupplyBefore = await bammToken.totalSupply();
const lusdBalanceBefore = await stabilityPool.getCompoundedLUSDDeposit(BAMM_ADDRESS);
const amount = ethers.utils.parseEther("10000");
const spells = [
{
connector: connectorName,
method: "deposit",
args: [amount, 0, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
const expectedBalance = totalSupplyBefore.mul(amount).div(lusdBalanceBefore)
expect(veryClose(expectedBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true
});
it("should deposit all LUSD", async function () {
const totalSupplyBefore = await bammToken.totalSupply();
const lusdBalanceBefore = await stabilityPool.getCompoundedLUSDDeposit(BAMM_ADDRESS);
const amount = web3.utils.toBN("2").pow(web3.utils.toBN("256")).sub(web3.utils.toBN("1"));
const balanceBefore = await bammToken.balanceOf(dsaWallet0.address)
const spells = [
{
connector: connectorName,
method: "deposit",
args: [amount, 0, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
const expectedBalance = (totalSupplyBefore.mul(ethers.utils.parseEther("90000")).div(lusdBalanceBefore)).add(balanceBefore)
expect(veryClose(expectedBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true
});
it("should withdraw half of the shares", async function () {
const balanceBefore = await bammToken.balanceOf(dsaWallet0.address)
const halfBalance = balanceBefore.div("2")
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [halfBalance, 0, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(veryClose(halfBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true
expect(veryClose(ethers.utils.parseEther("50000"), await lusd.balanceOf(dsaWallet0.address))).to.be.true
});
it("should withdraw all the shares", async function () {
const amount = web3.utils.toBN("2").pow(web3.utils.toBN("256")).sub(web3.utils.toBN("1"));
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [amount, 0, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(veryClose(ethers.utils.parseEther("100000"), await lusd.balanceOf(dsaWallet0.address))).to.be.true
});
})
})
function veryClose(n1, n2) {
n1 = web3.utils.toBN(n1)
n2 = web3.utils.toBN(n2)
_10000 = web3.utils.toBN(10000)
_9999 = web3.utils.toBN(9999)
if(n1.mul(_10000).lt(n2.mul(_9999))) return false
if(n2.mul(_10000).lt(n1.mul(_9999))) return false
return true
}

View File

@ -0,0 +1,326 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { web3, deployments, waffle, ethers } = hre;
const { provider, deployContract } = waffle
const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/buildDSAv2")
const encodeSpells = require("../../scripts/encodeSpells.js")
const getMasterSigner = require("../../scripts/getMasterSigner")
const addresses = require("../../scripts/constant/addresses");
const abis = require("../../scripts/constant/abis");
const constants = require("../../scripts/constant/constant");
const tokens = require("../../scripts/constant/tokens");
const connectorMakerArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/main.sol/ConnectV1BMakerDAO.json")
describe("B.Maker", function () {
const connectorName = "B.MAKER-TEST-A"
let dsaWallet0;
let dsaWallet1;
let masterSigner;
let instaConnectorsV2;
let connector;
let manager;
let vat;
let dai;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
masterSigner = await getMasterSigner(wallet3)
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: connectorMakerArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
manager = await ethers.getContractAt("BManagerLike", "0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed")
vat = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol:VatLike", await manager.vat())
dai = await ethers.getContractAt("../artifacts/contracts/mainnet/common/interfaces.sol:TokenInterface", tokens.dai.address)
console.log("Connector address", connector.address)
})
it("test veryClose.", async function () {
expect(veryClose(1000001, 1000000)).to.be.true
expect(veryClose(1000000, 1000001)).to.be.true
expect(veryClose(1003000, 1000001)).to.be.false
expect(veryClose(1000001, 1000300)).to.be.false
});
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
expect(await connector.name()).to.be.equal("B.MakerDAO-v1.0");
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
dsaWallet1 = await buildDSAv2(wallet1.address)
expect(!!dsaWallet1.address).to.be.true;
});
it("Deposit ETH into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
await wallet1.sendTransaction({
to: dsaWallet1.address,
value: ethers.utils.parseEther("10")
});
expect(await ethers.provider.getBalance(dsaWallet1.address)).to.be.gte(ethers.utils.parseEther("10"));
});
});
describe("Main", function () {
let vault
let ilk
let urn
it("Should open ETH-A vault Maker", async function () {
vault = Number(await manager.cdpi()) + 1
const spells = [
{
connector: connectorName,
method: "open",
args: ["ETH-A"]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await manager.owns(vault)).to.be.equal(dsaWallet0.address)
ilk = await manager.ilks(vault)
expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000")
urn = await manager.urns(vault)
});
it("Should deposit", async function () {
const amount = ethers.utils.parseEther("7") // 7 ETH
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "deposit",
args: [vault, amount, 0, setId]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("3"))
const urnData = await vat.urns(ilk, urn)
expect(urnData[0]).to.be.equal(amount) // ink
expect(urnData[1]).to.be.equal("0") // art
});
it("Should withdraw", async function () {
const amount = ethers.utils.parseEther("1") // 1 ETH
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "withdraw",
args: [vault, amount, 0, setId]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("4"))
const urnData = await vat.urns(ilk, urn)
expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink
expect(urnData[1]).to.be.equal("0") // art
});
it("Should borrow", async function () {
const amount = ethers.utils.parseEther("6000") // 6000 dai
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "borrow",
args: [vault, amount, 0, setId]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
const urnData = await vat.urns(ilk, urn)
expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink
expect(urnData[1]).to.be.equal(await daiToArt(vat, ilk, amount)) // art
expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(amount)
});
it("Should repay", async function () {
const amount = ethers.utils.parseEther("500") // 500 dai
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "payback",
args: [vault, amount, 0, setId]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
const urnData = await vat.urns(ilk, urn)
expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink
expect(urnData[1]).to.be.equal(await daiToArt(vat, ilk, ethers.utils.parseEther("5500"))) // art
expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(ethers.utils.parseEther("5500"))
});
it("Should depositAndBorrow", async function () {
const borrowAmount = ethers.utils.parseEther("1000") // 1000 dai
const depositAmount = ethers.utils.parseEther("1") // 1 dai
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "depositAndBorrow",
args: [vault, depositAmount, borrowAmount, 0, 0, 0, 0]
}
]
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
const urnData = await vat.urns(ilk, urn)
expect(urnData[0]).to.be.equal(ethers.utils.parseEther("7")) // ink
expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(ethers.utils.parseEther("6500"))
// calculation is not precise as the jug was dripped
expect(veryClose(urnData[1], await daiToArt(vat, ilk, ethers.utils.parseEther("6500")))).to.be.true
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("1"))
});
it("Should close", async function () {
// open a new vault
const newVault = vault + 1
let spells = [
{
connector: connectorName,
method: "open",
args: ["ETH-A"]
}
]
let tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address)
let receipt = await tx.wait()
expect(await manager.owns(newVault)).to.be.equal(dsaWallet1.address)
ilk = await manager.ilks(newVault)
expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000")
urn = await manager.urns(newVault)
// deposit and borrow
const borrowAmount = ethers.utils.parseEther("6000") // 6000 dai
const depositAmount = ethers.utils.parseEther("5") // 5 ETH
spells = [
{
connector: connectorName,
method: "depositAndBorrow",
args: [newVault, depositAmount, borrowAmount, 0, 0, 0, 0]
}
]
tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address)
receipt = await tx.wait()
const setId = 0
// repay borrow
spells = [
{
connector: connectorName,
method: "payback",
args: [newVault, borrowAmount, 0, setId]
}
]
tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address)
receipt = await tx.wait()
// withdraw deposit
spells = [
{
connector: connectorName,
method: "withdraw",
args: [newVault, depositAmount, 0, setId]
}
]
tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address)
receipt = await tx.wait()
// close
spells = [
{
connector: connectorName,
method: "close",
args: [newVault]
}
]
tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address)
receipt = await tx.wait()
expect(await manager.owns(newVault)).not.to.be.equal(dsaWallet1.address)
});
})
})
async function daiToArt(vat, ilk, dai) {
const ilks = await vat.ilks(ilk)
const rate = ilks[1] // second parameter
const _1e27 = ethers.utils.parseEther("1000000000") // 1e9 * 1e18
const art = dai.mul(_1e27).div(rate)
return art.add(1)
}
function veryClose(n1, n2) {
n1 = web3.utils.toBN(n1)
n2 = web3.utils.toBN(n2)
_10000 = web3.utils.toBN(10000)
_9999 = web3.utils.toBN(9999)
if(n1.mul(_10000).lt(n2.mul(_9999))) return false
if(n2.mul(_10000).lt(n1.mul(_9999))) return false
return true
}

View File

@ -1208,7 +1208,7 @@ describe("Liquity", () => {
const depositAmount = 0;
const borrowAmount = 0;
const withdrawAmount = ethers.utils.parseEther("1"); // 1 ETH;
const repayAmount = ethers.utils.parseUnits("500", 18); // 500 LUSD;
const repayAmount = ethers.utils.parseUnits("10", 18); // 10 LUSD;
const { upperHint, lowerHint } = await helpers.getTroveInsertionHints(
troveCollateralBefore.sub(withdrawAmount),
troveDebtBefore.sub(repayAmount),
@ -1256,7 +1256,7 @@ describe("Liquity", () => {
expect(
troveDebt,
`Trove debt should have increased by at least ${borrowAmount} ETH`
`Trove debt should have decreased by at least ${repayAmount} LUSD`
).to.gte(expectedTroveDebt);
});
@ -1273,7 +1273,7 @@ describe("Liquity", () => {
const depositAmount = ethers.utils.parseEther("1"); // 1 ETH
const borrowAmount = 0;
const withdrawAmount = 0;
const repayAmount = ethers.utils.parseUnits("100", 18); // 100 lUSD
const repayAmount = ethers.utils.parseUnits("10", 18); // 10 lUSD
const upperHint = ethers.constants.AddressZero;
const lowerHint = ethers.constants.AddressZero;
const maxFeePercentage = ethers.utils.parseUnits("0.5", 18); // 0.5% max fee
@ -1304,7 +1304,7 @@ describe("Liquity", () => {
0, // Repay amount comes from a previous spell's storage slot
upperHint,
lowerHint,
[ethDepositId, 0, 0, 0],
[ethDepositId, 0, 0, lusdRepayId],
[0, 0, 0, 0],
],
};
@ -1323,7 +1323,7 @@ describe("Liquity", () => {
.connect(userWallet)
.approve(dsa.address, repayAmount);
// Adjust Trove by depositing ETH and borrowing LUSD
// Adjust Trove by depositing ETH and repaying LUSD
await dsa
.connect(userWallet)
.cast(...encodeSpells(spells), userWallet.address, {
@ -1338,7 +1338,7 @@ describe("Liquity", () => {
dsa.address
);
const expectedTroveColl = troveCollateralBefore.add(depositAmount);
const expectedTroveDebt = troveDebtBefore.add(borrowAmount);
const expectedTroveDebt = troveDebtBefore.sub(repayAmount);
expect(
troveCollateral,
@ -1347,7 +1347,7 @@ describe("Liquity", () => {
expect(
troveDebt,
`Trove debt should have increased by at least ${borrowAmount} ETH`
`Trove debt (${troveDebtBefore}) should have decreased by at least ${repayAmount} LUSD`
).to.eq(expectedTroveDebt);
});