mirror of
https://github.com/Instadapp/dsa-connectors.git
synced 2024-07-29 22:37:00 +00:00
fix conflicts
This commit is contained in:
commit
3db7b4104a
51
.github/workflows/comment-pr.yml
vendored
Normal file
51
.github/workflows/comment-pr.yml
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
name: Comment on PR
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["PR status checks"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
${{ github.event.workflow_run.event == 'pull_request' &&
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
}}
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
let artifacts = await github.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: ${{ github.event.workflow_run.id }},
|
||||
});
|
||||
let artifact = artifacts.data.artifacts.filter(artifact => {
|
||||
return artifact.name == "pr"
|
||||
})[0];
|
||||
let download = await github.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: artifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
let fs = require('fs');
|
||||
fs.writeFileSync('${{ github.workspace }}/pr.zip', Buffer.from(download.data));
|
||||
- run: unzip pr.zip
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
let fs = require('fs');
|
||||
let prNumber = Number(fs.readFileSync("./number"));
|
||||
let statusCheck = fs.readFileSync("./status-check-output");
|
||||
await github.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
body: '```' + statusCheck + '```',
|
||||
});
|
27
.github/workflows/status.yml
vendored
27
.github/workflows/status.yml
vendored
|
@ -1,12 +1,13 @@
|
|||
name: PR status checks
|
||||
on:
|
||||
# This is so the status check can run on forks.
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
|
@ -31,21 +32,13 @@ jobs:
|
|||
- name: Run status checks
|
||||
id: status_check
|
||||
run: |
|
||||
mkdir -p pr
|
||||
# Run status checks, Remove ANSI colors from the text
|
||||
output=$(node ./status-checks | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g')
|
||||
# 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
|
||||
output=$(npx ts-node ./status-checks/index.ts | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g')
|
||||
cat <<< "$output" > "./pr/status-check-output"
|
||||
echo ${{ github.event.number }} > ./pr/number
|
||||
- uses: actions/upload-artifact@v2
|
||||
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 }}```"
|
||||
name: pr
|
||||
path: pr/
|
||||
retention-days: 1
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -63,4 +63,5 @@ build/contracts
|
|||
# buidler
|
||||
artifacts
|
||||
cache
|
||||
typechain
|
||||
typechain
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogSwap(
|
||||
address indexed buyToken,
|
||||
address indexed sellToken,
|
||||
uint256 buyAmt,
|
||||
uint256 sellAmt,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../../common/interfaces.sol";
|
||||
import { DSMath } from "../../../common/math.sol";
|
||||
import { Basic } from "../../../common/basic.sol";
|
||||
import { SwapData } from "./interface.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
/**
|
||||
* @dev UniswapV3 Swap Router Address
|
||||
*/
|
||||
address internal constant V3_SWAP_ROUTER_ADDRESS =
|
||||
0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
|
||||
|
||||
/**
|
||||
* @dev UniswapV3 swapHelper
|
||||
* @param swapData - Struct defined in interfaces.sol
|
||||
*/
|
||||
function _swapHelper(SwapData memory swapData)
|
||||
internal
|
||||
returns (uint256 buyAmt)
|
||||
{
|
||||
(uint256 _buyDec, uint256 _sellDec) = getTokensDec(
|
||||
swapData.buyToken,
|
||||
swapData.sellToken
|
||||
);
|
||||
uint256 _sellAmt18 = convertTo18(_sellDec, swapData._sellAmt);
|
||||
uint256 _slippageAmt = convert18ToDec(
|
||||
_buyDec,
|
||||
wmul(swapData.unitAmt, _sellAmt18)
|
||||
);
|
||||
|
||||
uint256 initalBal = getTokenBal(swapData.buyToken);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
(bool success, ) = V3_SWAP_ROUTER_ADDRESS.call(swapData.callData);
|
||||
if (!success) revert("uniswapV3-swap-failed");
|
||||
|
||||
uint256 finalBal = getTokenBal(swapData.buyToken);
|
||||
|
||||
buyAmt = sub(finalBal, initalBal);
|
||||
require(_slippageAmt <= buyAmt, "Too much slippage");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the swapping data from auto router sdk
|
||||
* @param swapData Struct with multiple swap data defined in interfaces.sol
|
||||
* @param setId Set token amount at this ID in `InstaMemory` Contract.
|
||||
*/
|
||||
function _swap(SwapData memory swapData, uint256 setId)
|
||||
internal
|
||||
returns (SwapData memory)
|
||||
{
|
||||
bool isEthSellToken = address(swapData.sellToken) == ethAddr;
|
||||
bool isEthBuyToken = address(swapData.buyToken) == ethAddr;
|
||||
|
||||
swapData.sellToken = isEthSellToken
|
||||
? TokenInterface(wethAddr)
|
||||
: swapData.sellToken;
|
||||
swapData.buyToken = isEthBuyToken
|
||||
? TokenInterface(wethAddr)
|
||||
: swapData.buyToken;
|
||||
|
||||
convertEthToWeth(isEthSellToken, swapData.sellToken, swapData._sellAmt);
|
||||
|
||||
approve(
|
||||
TokenInterface(swapData.sellToken),
|
||||
V3_SWAP_ROUTER_ADDRESS,
|
||||
swapData._sellAmt
|
||||
);
|
||||
|
||||
swapData._buyAmt = _swapHelper(swapData);
|
||||
|
||||
convertWethToEth(isEthBuyToken, swapData.buyToken, swapData._buyAmt);
|
||||
|
||||
setUint(setId, swapData._buyAmt);
|
||||
|
||||
return swapData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../../common/interfaces.sol";
|
||||
|
||||
struct SwapData {
|
||||
TokenInterface sellToken;
|
||||
TokenInterface buyToken;
|
||||
uint256 _sellAmt;
|
||||
uint256 _buyAmt;
|
||||
uint256 unitAmt;
|
||||
bytes callData;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
/**
|
||||
* @title UniswapV3_autoRouter.
|
||||
* @dev DEX.
|
||||
*/
|
||||
|
||||
// import files from common directory
|
||||
import { TokenInterface, MemoryInterface } from "../../../common/interfaces.sol";
|
||||
import { Stores } from "../../../common/stores.sol";
|
||||
import { SwapData } from "./interface.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
abstract contract AutoRouter is Helpers, Events {
|
||||
/**
|
||||
* @dev Sell ETH/ERC20_Token using uniswap v3 auto router.
|
||||
* @notice Swap tokens from getting an optimized trade routes
|
||||
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param sellAmt The amount of the token to sell.
|
||||
* @param unitAmt The amount of buyAmt/sellAmt with slippage.
|
||||
* @param callData Data from Uniswap V3 auto router SDK.
|
||||
* @param setId ID stores the amount of token brought.
|
||||
*/
|
||||
function sell(
|
||||
address buyAddr,
|
||||
address sellAddr,
|
||||
uint256 sellAmt,
|
||||
uint256 unitAmt,
|
||||
bytes calldata callData,
|
||||
uint256 setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
SwapData memory swapData = SwapData({
|
||||
buyToken: TokenInterface(buyAddr),
|
||||
sellToken: TokenInterface(sellAddr),
|
||||
unitAmt: unitAmt,
|
||||
callData: callData,
|
||||
_sellAmt: sellAmt,
|
||||
_buyAmt: 0
|
||||
});
|
||||
|
||||
swapData = _swap(swapData, setId);
|
||||
|
||||
_eventName = "LogSwap(address,address,uint256,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(
|
||||
buyAddr,
|
||||
sellAddr,
|
||||
swapData._buyAmt,
|
||||
swapData._sellAmt,
|
||||
0,
|
||||
setId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2UniswapV3AutoRouterArbitrum is AutoRouter {
|
||||
string public name = "UniswapV3-Auto-Router-v1";
|
||||
}
|
6
contracts/fantom/connectors/authority/events.sol
Normal file
6
contracts/fantom/connectors/authority/events.sol
Normal file
|
@ -0,0 +1,6 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogAddAuth(address indexed _msgSender, address indexed _authority);
|
||||
event LogRemoveAuth(address indexed _msgSender, address indexed _authority);
|
||||
}
|
15
contracts/fantom/connectors/authority/helpers.sol
Normal file
15
contracts/fantom/connectors/authority/helpers.sol
Normal file
|
@ -0,0 +1,15 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
import { ListInterface } from "./interface.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
ListInterface internal constant listContract = ListInterface(0x3565F6057b7fFE36984779A507fC87b31EFb0f09);
|
||||
|
||||
function checkAuthCount() internal view returns (uint count) {
|
||||
uint64 accountId = listContract.accountID(address(this));
|
||||
count = listContract.accountLink(accountId).count;
|
||||
}
|
||||
}
|
13
contracts/fantom/connectors/authority/interface.sol
Normal file
13
contracts/fantom/connectors/authority/interface.sol
Normal file
|
@ -0,0 +1,13 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface ListInterface {
|
||||
struct AccountLink {
|
||||
address first;
|
||||
address last;
|
||||
uint64 count;
|
||||
}
|
||||
|
||||
function accountID(address) external view returns (uint64);
|
||||
function accountLink(uint64) external view returns (AccountLink memory);
|
||||
}
|
45
contracts/fantom/connectors/authority/main.sol
Normal file
45
contracts/fantom/connectors/authority/main.sol
Normal file
|
@ -0,0 +1,45 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
/**
|
||||
* @title Authority.
|
||||
* @dev Manage Authorities to DSA.
|
||||
*/
|
||||
|
||||
import { AccountInterface } from "../../common/interfaces.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
abstract contract AuthorityResolver is Events, Helpers {
|
||||
/**
|
||||
* @dev Add New authority
|
||||
* @notice Add an address as account authority
|
||||
* @param authority The authority Address.
|
||||
*/
|
||||
function add(
|
||||
address authority
|
||||
) external payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
AccountInterface(address(this)).enable(authority);
|
||||
|
||||
_eventName = "LogAddAuth(address,address)";
|
||||
_eventParam = abi.encode(msg.sender, authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Remove authority
|
||||
* @notice Remove an address as account authority
|
||||
* @param authority The authority Address.
|
||||
*/
|
||||
function remove(
|
||||
address authority
|
||||
) external payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
require(checkAuthCount() > 1, "Removing-all-authorities");
|
||||
AccountInterface(address(this)).disable(authority);
|
||||
|
||||
_eventName = "LogRemoveAuth(address,address)";
|
||||
_eventParam = abi.encode(msg.sender, authority);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2AuthFantom is AuthorityResolver {
|
||||
string public constant name = "Auth-v1";
|
||||
}
|
20
contracts/fantom/connectors/basic-ERC1155/events.sol
Normal file
20
contracts/fantom/connectors/basic-ERC1155/events.sol
Normal file
|
@ -0,0 +1,20 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogDepositERC1155(
|
||||
address indexed erc1155,
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
event LogWithdrawERC1155(
|
||||
address indexed erc1155,
|
||||
uint256 tokenId,
|
||||
address indexed to,
|
||||
uint256 amount,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
}
|
93
contracts/fantom/connectors/basic-ERC1155/main.sol
Normal file
93
contracts/fantom/connectors/basic-ERC1155/main.sol
Normal file
|
@ -0,0 +1,93 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
/**
|
||||
* @title Basic.
|
||||
* @dev Deposit & Withdraw from ERC1155 DSA.
|
||||
*/
|
||||
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
|
||||
|
||||
import {DSMath} from "../../common/math.sol";
|
||||
import {Basic} from "../../common/basic.sol";
|
||||
import {Events} from "./events.sol";
|
||||
|
||||
abstract contract BasicResolver is Events, DSMath, Basic {
|
||||
/**
|
||||
* @dev Deposit Assets To Smart Account.
|
||||
* @notice Deposit a ERC1155 token to DSA
|
||||
* @param token Address of token.
|
||||
* @param tokenId ID of token.
|
||||
* @param amount Amount to deposit.
|
||||
* @param getId ID to retrieve amount.
|
||||
* @param setId ID stores the amount.
|
||||
*/
|
||||
function depositERC1155(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 amount,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 _amount = getUint(getId, amount);
|
||||
|
||||
IERC1155 tokenContract = IERC1155(token);
|
||||
tokenContract.safeTransferFrom(
|
||||
msg.sender,
|
||||
address(this),
|
||||
tokenId,
|
||||
_amount,
|
||||
""
|
||||
);
|
||||
|
||||
setUint(setId, _amount);
|
||||
|
||||
_eventName = "LogDepositERC1155(address,address,uint256,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(
|
||||
token,
|
||||
msg.sender,
|
||||
tokenId,
|
||||
_amount,
|
||||
getId,
|
||||
setId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw Assets To Smart Account.
|
||||
* @notice Withdraw a ERC1155 token from DSA
|
||||
* @param token Address of the token.
|
||||
* @param tokenId ID of token.
|
||||
* @param to The address to receive the token upon withdrawal
|
||||
* @param amount Amount to withdraw.
|
||||
* @param getId ID to retrieve amount.
|
||||
* @param setId ID stores the amount.
|
||||
*/
|
||||
function withdrawERC1155(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
address payable to,
|
||||
uint256 amount,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 _amount = getUint(getId, amount);
|
||||
IERC1155 tokenContract = IERC1155(token);
|
||||
tokenContract.safeTransferFrom(address(this), to, tokenId, _amount, "");
|
||||
|
||||
setUint(setId, _amount);
|
||||
|
||||
_eventName = "LogWithdrawERC1155(address,uint256,address,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(token, tokenId, to, _amount, getId, setId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2BasicERC1155Fantom is BasicResolver {
|
||||
string public constant name = "BASIC-ERC1155-v1.0";
|
||||
}
|
18
contracts/fantom/connectors/basic-ERC721/events.sol
Normal file
18
contracts/fantom/connectors/basic-ERC721/events.sol
Normal file
|
@ -0,0 +1,18 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogDepositERC721(
|
||||
address indexed erc721,
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
event LogWithdrawERC721(
|
||||
address indexed erc721,
|
||||
uint256 tokenId,
|
||||
address indexed to,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
}
|
76
contracts/fantom/connectors/basic-ERC721/main.sol
Normal file
76
contracts/fantom/connectors/basic-ERC721/main.sol
Normal file
|
@ -0,0 +1,76 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
/**
|
||||
* @title Basic.
|
||||
* @dev Deposit & Withdraw ERC721 from DSA.
|
||||
*/
|
||||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
|
||||
import {DSMath} from "../../common/math.sol";
|
||||
import {Basic} from "../../common/basic.sol";
|
||||
import {Events} from "./events.sol";
|
||||
|
||||
abstract contract BasicResolver is Events, DSMath, Basic {
|
||||
/**
|
||||
* @dev Deposit Assets To Smart Account.
|
||||
* @notice Deposit a ERC721 token to DSA
|
||||
* @param token Address of token.
|
||||
* @param tokenId ID of token.
|
||||
* @param getId ID to retrieve tokenId.
|
||||
* @param setId ID stores the tokenId.
|
||||
*/
|
||||
function depositERC721(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 _tokenId = getUint(getId, tokenId);
|
||||
|
||||
IERC721 tokenContract = IERC721(token);
|
||||
tokenContract.safeTransferFrom(msg.sender, address(this), _tokenId);
|
||||
|
||||
setUint(setId, _tokenId);
|
||||
|
||||
_eventName = "LogDepositERC721(address,address,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(token, msg.sender, _tokenId, getId, setId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw Assets To Smart Account.
|
||||
* @notice Withdraw a ERC721 token from DSA
|
||||
* @param token Address of the token.
|
||||
* @param tokenId ID of token.
|
||||
* @param to The address to receive the token upon withdrawal
|
||||
* @param getId ID to retrieve tokenId.
|
||||
* @param setId ID stores the tokenId.
|
||||
*/
|
||||
function withdrawERC721(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
address payable to,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 _tokenId = getUint(getId, tokenId);
|
||||
IERC721 tokenContract = IERC721(token);
|
||||
tokenContract.safeTransferFrom(address(this), to, _tokenId);
|
||||
|
||||
setUint(setId, _tokenId);
|
||||
|
||||
_eventName = "LogWithdrawERC721(address,uint256,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(token, _tokenId, to, getId, setId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2BasicERC721Fantom is BasicResolver {
|
||||
string public constant name = "BASIC-ERC721-v1.0";
|
||||
}
|
6
contracts/fantom/connectors/basic/events.sol
Normal file
6
contracts/fantom/connectors/basic/events.sol
Normal file
|
@ -0,0 +1,6 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(address indexed erc20, uint256 tokenAmt, uint256 getId, uint256 setId);
|
||||
event LogWithdraw(address indexed erc20, uint256 tokenAmt, address indexed to, uint256 getId, uint256 setId);
|
||||
}
|
82
contracts/fantom/connectors/basic/main.sol
Normal file
82
contracts/fantom/connectors/basic/main.sol
Normal file
|
@ -0,0 +1,82 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
|
||||
/**
|
||||
* @title Basic.
|
||||
* @dev Deposit & Withdraw from DSA.
|
||||
*/
|
||||
|
||||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
abstract contract BasicResolver is Events, DSMath, Basic {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
/**
|
||||
* @dev Deposit Assets To Smart Account.
|
||||
* @notice Deposit a token to DSA
|
||||
* @param token The address of the token to deposit. (For MATIC: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for MATIC))
|
||||
* @param getId ID to retrieve amt.
|
||||
* @param setId ID stores the amount of tokens deposited.
|
||||
*/
|
||||
function deposit(
|
||||
address token,
|
||||
uint256 amt,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
) public payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
uint _amt = getUint(getId, amt);
|
||||
if (token != ftmAddr) {
|
||||
IERC20 tokenContract = IERC20(token);
|
||||
_amt = _amt == uint(-1) ? tokenContract.balanceOf(msg.sender) : _amt;
|
||||
tokenContract.safeTransferFrom(msg.sender, address(this), _amt);
|
||||
} else {
|
||||
require(msg.value == _amt || _amt == uint(-1), "invalid-ether-amount");
|
||||
_amt = msg.value;
|
||||
}
|
||||
setUint(setId, _amt);
|
||||
|
||||
_eventName = "LogDeposit(address,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(token, _amt, getId, setId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw Assets from Smart Account
|
||||
* @notice Withdraw a token from DSA
|
||||
* @param token The address of the token to withdraw. (For MATIC: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param amt The amount of tokens to withdraw. (For max: `uint256(-1)`)
|
||||
* @param to The address to receive the token upon withdrawal
|
||||
* @param getId ID to retrieve amt.
|
||||
* @param setId ID stores the amount of tokens withdrawn.
|
||||
*/
|
||||
function withdraw(
|
||||
address token,
|
||||
uint amt,
|
||||
address payable to,
|
||||
uint getId,
|
||||
uint setId
|
||||
) public payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
uint _amt = getUint(getId, amt);
|
||||
if (token == ftmAddr) {
|
||||
_amt = _amt == uint(-1) ? address(this).balance : _amt;
|
||||
to.call{value: _amt}("");
|
||||
} else {
|
||||
IERC20 tokenContract = IERC20(token);
|
||||
_amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt;
|
||||
tokenContract.safeTransfer(to, _amt);
|
||||
}
|
||||
setUint(setId, _amt);
|
||||
|
||||
_eventName = "LogWithdraw(address,uint256,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(token, _amt, to, getId, setId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2BasicFantom is BasicResolver {
|
||||
string constant public name = "Basic-v1";
|
||||
}
|
6
contracts/fantom/connectors/wftm/events.sol
Normal file
6
contracts/fantom/connectors/wftm/events.sol
Normal file
|
@ -0,0 +1,6 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(uint256 tokenAmt, uint256 getId, uint256 setId);
|
||||
event LogWithdraw(uint256 tokenAmt, uint256 getId, uint256 setId);
|
||||
}
|
8
contracts/fantom/connectors/wftm/helpers.sol
Normal file
8
contracts/fantom/connectors/wftm/helpers.sol
Normal file
|
@ -0,0 +1,8 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
|
||||
|
||||
abstract contract Helpers {
|
||||
TokenInterface constant internal wftmContract = TokenInterface(0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83);
|
||||
}
|
65
contracts/fantom/connectors/wftm/main.sol
Normal file
65
contracts/fantom/connectors/wftm/main.sol
Normal file
|
@ -0,0 +1,65 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
/**
|
||||
* @title WFTM.
|
||||
* @dev Wrap and Unwrap WFTM.
|
||||
*/
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
import { Events } from "./events.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
|
||||
abstract contract Resolver is Events, DSMath, Basic, Helpers {
|
||||
|
||||
/**
|
||||
* @dev Deposit FTM into WFTM.
|
||||
* @notice Wrap FTM into WFTM
|
||||
* @param amt The amount of FTM to deposit. (For max: `uint256(-1)`)
|
||||
* @param getId ID to retrieve amt.
|
||||
* @param setId ID stores the amount of FTM deposited.
|
||||
*/
|
||||
function deposit(
|
||||
uint256 amt,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
) public payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
uint _amt = getUint(getId, amt);
|
||||
|
||||
_amt = _amt == uint(-1) ? address(this).balance : _amt;
|
||||
wftmContract.deposit{value: _amt}();
|
||||
|
||||
setUint(setId, _amt);
|
||||
|
||||
_eventName = "LogDeposit(uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(_amt, getId, setId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw FTM from WFTM from Smart Account
|
||||
* @notice Unwrap FTM from WFTM
|
||||
* @param amt The amount of wFTM to withdraw. (For max: `uint256(-1)`)
|
||||
* @param getId ID to retrieve amt.
|
||||
* @param setId ID stores the amount of FTM withdrawn.
|
||||
*/
|
||||
function withdraw(
|
||||
uint amt,
|
||||
uint getId,
|
||||
uint setId
|
||||
) public payable returns (string memory _eventName, bytes memory _eventParam) {
|
||||
uint _amt = getUint(getId, amt);
|
||||
|
||||
_amt = _amt == uint(-1) ? wftmContract.balanceOf(address(this)) : _amt;
|
||||
approve(wftmContract, wftmAddr, _amt);
|
||||
wftmContract.withdraw(_amt);
|
||||
|
||||
setUint(setId, _amt);
|
||||
|
||||
_eventName = "LogWithdraw(uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(_amt, getId, setId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2WFTMFantom is Resolver {
|
||||
string constant public name = "WFTM-v1.0";
|
||||
}
|
5
contracts/mainnet/connectors/lido_stETH/events.sol
Normal file
5
contracts/mainnet/connectors/lido_stETH/events.sol
Normal file
|
@ -0,0 +1,5 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(uint256 Amt, uint256 getId, uint256 setId);
|
||||
}
|
12
contracts/mainnet/connectors/lido_stETH/helpers.sol
Normal file
12
contracts/mainnet/connectors/lido_stETH/helpers.sol
Normal file
|
@ -0,0 +1,12 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
import { ILido } from "./interface.sol";
|
||||
|
||||
abstract contract Helpers {
|
||||
ILido internal constant lidoInterface =
|
||||
ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);
|
||||
|
||||
address internal constant treasury =
|
||||
0x28849D2b63fA8D361e5fc15cB8aBB13019884d09; // Instadapp's treasury address
|
||||
}
|
5
contracts/mainnet/connectors/lido_stETH/interface.sol
Normal file
5
contracts/mainnet/connectors/lido_stETH/interface.sol
Normal file
|
@ -0,0 +1,5 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
interface ILido {
|
||||
function submit(address _referral) external payable returns (uint256);
|
||||
}
|
43
contracts/mainnet/connectors/lido_stETH/main.sol
Normal file
43
contracts/mainnet/connectors/lido_stETH/main.sol
Normal file
|
@ -0,0 +1,43 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
/**
|
||||
* @title Stake Eth.
|
||||
* @dev deposit Eth into lido and in return you get equivalent of stEth tokens
|
||||
*/
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
import { Events } from "./events.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
|
||||
abstract contract Resolver is Events, DSMath, Basic, Helpers {
|
||||
/**
|
||||
* @dev deposit ETH into Lido.
|
||||
* @notice sends Eth into lido and in return you get equivalent of stEth tokens
|
||||
* @param amt The amount of ETH to deposit. (For max: `uint256(-1)`)
|
||||
* @param getId ID to retrieve amt.
|
||||
* @param setId ID stores the amount of ETH deposited.
|
||||
*/
|
||||
function deposit(
|
||||
uint256 amt,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 _amt = getUint(getId, amt);
|
||||
|
||||
_amt = _amt == uint256(-1) ? address(this).balance : _amt;
|
||||
lidoInterface.submit{ value: amt }(treasury);
|
||||
setUint(setId, _amt);
|
||||
|
||||
_eventName = "LogDeposit(uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(_amt, getId, setId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2LidoStEth is Resolver {
|
||||
string public constant name = "LidoStEth-v1";
|
||||
}
|
18
contracts/mainnet/connectors/mstable/events.sol
Normal file
18
contracts/mainnet/connectors/mstable/events.sol
Normal file
|
@ -0,0 +1,18 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(address token, uint256 amount, address path, bool stake);
|
||||
event LogWithdraw(
|
||||
address token,
|
||||
uint256 amount,
|
||||
address path,
|
||||
bool unstake
|
||||
);
|
||||
event LogClaimRewards(address token, uint256 amount);
|
||||
event LogSwap(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amountIn,
|
||||
uint256 amountOut
|
||||
);
|
||||
}
|
109
contracts/mainnet/connectors/mstable/helpers.sol
Normal file
109
contracts/mainnet/connectors/mstable/helpers.sol
Normal file
|
@ -0,0 +1,109 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
import { ISavingsContractV2, IBoostedSavingsVault } from "./interface.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
address internal constant mUsdToken =
|
||||
0xe2f2a5C287993345a840Db3B0845fbC70f5935a5;
|
||||
address internal constant imUsdToken =
|
||||
0x30647a72Dc82d7Fbb1123EA74716aB8A317Eac19;
|
||||
address internal constant imUsdVault =
|
||||
0x78BefCa7de27d07DC6e71da295Cc2946681A6c7B;
|
||||
|
||||
/***************************************
|
||||
Internal
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save from any asset
|
||||
* @notice Called internally from deposit functions
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _path Path to mint mUSD (only needed for Feeder Pool)
|
||||
* @param _stake stake token in Vault?
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function _deposit(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
address _path,
|
||||
bool _stake
|
||||
) internal returns (string memory _eventName, bytes memory _eventParam) {
|
||||
// 1. Deposit mUSD to Save
|
||||
approve(TokenInterface(mUsdToken), imUsdToken, _amount);
|
||||
uint256 credits = ISavingsContractV2(imUsdToken).depositSavings(
|
||||
_amount
|
||||
);
|
||||
|
||||
if (_stake) {
|
||||
// 2. Stake imUSD to Vault
|
||||
approve(TokenInterface(imUsdToken), imUsdVault, credits);
|
||||
IBoostedSavingsVault(imUsdVault).stake(credits);
|
||||
}
|
||||
// 3. Log Events
|
||||
_eventName = "LogDeposit(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(_token, _amount, _path, _stake);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws from Save
|
||||
* @notice Withdraws token supported by mStable from Save
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _unstake unstake from Vault?
|
||||
* @return amountWithdrawn Amount withdrawn in mUSD
|
||||
*/
|
||||
|
||||
function _withdraw(uint256 _credits, bool _unstake)
|
||||
internal
|
||||
returns (uint256 amountWithdrawn)
|
||||
{
|
||||
uint256 credits;
|
||||
// 1. Withdraw from Vault
|
||||
if (_unstake) {
|
||||
credits = _credits == uint256(-1)
|
||||
? TokenInterface(imUsdVault).balanceOf(address(this))
|
||||
: _credits;
|
||||
IBoostedSavingsVault(imUsdVault).withdraw(credits);
|
||||
}
|
||||
|
||||
// 2. Withdraw from Save
|
||||
credits = _credits == uint256(-1)
|
||||
? TokenInterface(imUsdToken).balanceOf(address(this))
|
||||
: _credits;
|
||||
approve(TokenInterface(imUsdToken), imUsdVault, _credits);
|
||||
amountWithdrawn = ISavingsContractV2(imUsdToken).redeemCredits(credits);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the reward tokens
|
||||
* @notice Gets the reward tokens from the vault contract
|
||||
* @return rewardToken Address of reward token
|
||||
*/
|
||||
|
||||
function _getRewardTokens() internal view returns (address rewardToken) {
|
||||
rewardToken = address(
|
||||
IBoostedSavingsVault(imUsdVault).getRewardToken()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the internal balances of the rewardToken and platformToken
|
||||
* @notice Gets current balances of rewardToken and platformToken, used for calculating rewards accrued
|
||||
* @param _rewardToken Address of reward token
|
||||
* @return a Amount of reward token
|
||||
*/
|
||||
|
||||
function _getRewardInternalBal(address _rewardToken)
|
||||
internal
|
||||
view
|
||||
returns (uint256 a)
|
||||
{
|
||||
a = TokenInterface(_rewardToken).balanceOf(address(this));
|
||||
}
|
||||
}
|
379
contracts/mainnet/connectors/mstable/interface.sol
Normal file
379
contracts/mainnet/connectors/mstable/interface.sol
Normal file
|
@ -0,0 +1,379 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
interface IMasset {
|
||||
function mint(
|
||||
address _input,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function mintMulti(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function getMintOutput(address _input, uint256 _inputQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 mintOutput);
|
||||
|
||||
function getMintMultiOutput(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities
|
||||
) external view returns (uint256 mintOutput);
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 swapOutput);
|
||||
|
||||
function getSwapOutput(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity
|
||||
) external view returns (uint256 swapOutput);
|
||||
|
||||
function redeem(
|
||||
address _output,
|
||||
uint256 _mAssetQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 outputQuantity);
|
||||
|
||||
function redeemMasset(
|
||||
uint256 _mAssetQuantity,
|
||||
uint256[] calldata _minOutputQuantities,
|
||||
address _recipient
|
||||
) external returns (uint256[] memory outputQuantities);
|
||||
|
||||
function redeemExactBassets(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities,
|
||||
uint256 _maxMassetQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mAssetRedeemed);
|
||||
|
||||
function getRedeemOutput(address _output, uint256 _mAssetQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 bAssetOutput);
|
||||
|
||||
function getRedeemExactBassetsOutput(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities
|
||||
) external view returns (uint256 mAssetAmount);
|
||||
|
||||
// Views
|
||||
// This return an index, could be used to check if it's part of the basket
|
||||
function bAssetIndexes(address) external view returns (uint8);
|
||||
|
||||
function getPrice() external view returns (uint256 price, uint256 k);
|
||||
}
|
||||
|
||||
interface ISavingsContractV2 {
|
||||
function depositInterest(uint256 _amount) external; // V1 & V2
|
||||
|
||||
function depositSavings(uint256 _amount)
|
||||
external
|
||||
returns (uint256 creditsIssued); // V1 & V2
|
||||
|
||||
function depositSavings(uint256 _amount, address _beneficiary)
|
||||
external
|
||||
returns (uint256 creditsIssued); // V2
|
||||
|
||||
function redeemCredits(uint256 _amount)
|
||||
external
|
||||
returns (uint256 underlyingReturned); // V2
|
||||
|
||||
function redeemUnderlying(uint256 _amount)
|
||||
external
|
||||
returns (uint256 creditsBurned); // V2
|
||||
|
||||
function exchangeRate() external view returns (uint256); // V1 & V2
|
||||
|
||||
function balanceOfUnderlying(address _user)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance); // V2
|
||||
|
||||
function underlyingToCredits(uint256 _credits)
|
||||
external
|
||||
view
|
||||
returns (uint256 underlying); // V2
|
||||
|
||||
function creditsToUnderlying(uint256 _underlying)
|
||||
external
|
||||
view
|
||||
returns (uint256 credits); // V2
|
||||
}
|
||||
|
||||
interface IBoostedSavingsVault {
|
||||
/**
|
||||
* @dev Stakes a given amount of the StakingToken for the sender
|
||||
* @param _amount Units of StakingToken
|
||||
*/
|
||||
function stake(uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @dev Stakes a given amount of the StakingToken for a given beneficiary
|
||||
* @param _beneficiary Staked tokens are credited to this address
|
||||
* @param _amount Units of StakingToken
|
||||
*/
|
||||
function stake(address _beneficiary, uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @dev Withdraws stake from pool and claims any unlocked rewards.
|
||||
* Note, this function is costly - the args for _claimRewards
|
||||
* should be determined off chain and then passed to other fn
|
||||
*/
|
||||
function exit() external;
|
||||
|
||||
/**
|
||||
* @dev Withdraws stake from pool and claims any unlocked rewards.
|
||||
* @param _first Index of the first array element to claim
|
||||
* @param _last Index of the last array element to claim
|
||||
*/
|
||||
function exit(uint256 _first, uint256 _last) external;
|
||||
|
||||
/**
|
||||
* @dev Withdraws given stake amount from the pool
|
||||
* @param _amount Units of the staked token to withdraw
|
||||
*/
|
||||
function withdraw(uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @dev Claims only the tokens that have been immediately unlocked, not including
|
||||
* those that are in the lockers.
|
||||
*/
|
||||
function claimReward() external;
|
||||
|
||||
/**
|
||||
* @dev Claims all unlocked rewards for sender.
|
||||
* Note, this function is costly - the args for _claimRewards
|
||||
* should be determined off chain and then passed to other fn
|
||||
*/
|
||||
function claimRewards() external;
|
||||
|
||||
/**
|
||||
* @dev Claims all unlocked rewards for sender. Both immediately unlocked
|
||||
* rewards and also locked rewards past their time lock.
|
||||
* @param _first Index of the first array element to claim
|
||||
* @param _last Index of the last array element to claim
|
||||
*/
|
||||
function claimRewards(uint256 _first, uint256 _last) external;
|
||||
|
||||
/**
|
||||
* @dev Pokes a given account to reset the boost
|
||||
*/
|
||||
function pokeBoost(address _account) external;
|
||||
|
||||
/**
|
||||
* @dev Gets the RewardsToken
|
||||
*/
|
||||
function getRewardToken() external view returns (IERC20);
|
||||
|
||||
/**
|
||||
* @dev Gets the last applicable timestamp for this reward period
|
||||
*/
|
||||
function lastTimeRewardApplicable() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Calculates the amount of unclaimed rewards per token since last update,
|
||||
* and sums with stored to give the new cumulative reward per token
|
||||
* @return 'Reward' per staked token
|
||||
*/
|
||||
function rewardPerToken() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returned the units of IMMEDIATELY claimable rewards a user has to receive. Note - this
|
||||
* does NOT include the majority of rewards which will be locked up.
|
||||
* @param _account User address
|
||||
* @return Total reward amount earned
|
||||
*/
|
||||
function earned(address _account) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Calculates all unclaimed reward data, finding both immediately unlocked rewards
|
||||
* and those that have passed their time lock.
|
||||
* @param _account User address
|
||||
* @return amount Total units of unclaimed rewards
|
||||
* @return first Index of the first userReward that has unlocked
|
||||
* @return last Index of the last userReward that has unlocked
|
||||
*/
|
||||
function unclaimedRewards(address _account)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256 amount,
|
||||
uint256 first,
|
||||
uint256 last
|
||||
);
|
||||
}
|
||||
|
||||
interface IFeederPool {
|
||||
// Mint
|
||||
function mint(
|
||||
address _input,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function mintMulti(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function getMintOutput(address _input, uint256 _inputQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 mintOutput);
|
||||
|
||||
function getMintMultiOutput(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities
|
||||
) external view returns (uint256 mintOutput);
|
||||
|
||||
// Swaps
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 swapOutput);
|
||||
|
||||
function getSwapOutput(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity
|
||||
) external view returns (uint256 swapOutput);
|
||||
|
||||
// Redemption
|
||||
function redeem(
|
||||
address _output,
|
||||
uint256 _fpTokenQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 outputQuantity);
|
||||
|
||||
function redeemProportionately(
|
||||
uint256 _fpTokenQuantity,
|
||||
uint256[] calldata _minOutputQuantities,
|
||||
address _recipient
|
||||
) external returns (uint256[] memory outputQuantities);
|
||||
|
||||
function redeemExactBassets(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities,
|
||||
uint256 _maxMassetQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mAssetRedeemed);
|
||||
|
||||
function getRedeemOutput(address _output, uint256 _fpTokenQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 bAssetOutput);
|
||||
|
||||
function getRedeemExactBassetsOutput(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities
|
||||
) external view returns (uint256 mAssetAmount);
|
||||
|
||||
// Views
|
||||
function mAsset() external view returns (address);
|
||||
|
||||
function getPrice() external view returns (uint256 price, uint256 k);
|
||||
}
|
||||
|
||||
interface IERC20 {
|
||||
/**
|
||||
* @dev Returns the amount of tokens in existence.
|
||||
*/
|
||||
function totalSupply() external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the amount of tokens owned by `account`.
|
||||
*/
|
||||
function balanceOf(address account) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Moves `amount` tokens from the caller's account to `recipient`.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function transfer(address recipient, uint256 amount)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Returns the remaining number of tokens that `spender` will be
|
||||
* allowed to spend on behalf of `owner` through {transferFrom}. This is
|
||||
* zero by default.
|
||||
*
|
||||
* This value changes when {approve} or {transferFrom} are called.
|
||||
*/
|
||||
function allowance(address owner, address spender)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
* IMPORTANT: Beware that changing an allowance with this method brings the risk
|
||||
* that someone may use both the old and the new allowance by unfortunate
|
||||
* transaction ordering. One possible solution to mitigate this race
|
||||
* condition is to first reduce the spender's allowance to 0 and set the
|
||||
* desired value afterwards:
|
||||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
||||
*
|
||||
* Emits an {Approval} event.
|
||||
*/
|
||||
function approve(address spender, uint256 amount) external returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Moves `amount` tokens from `sender` to `recipient` using the
|
||||
* allowance mechanism. `amount` is then deducted from the caller's
|
||||
* allowance.
|
||||
*
|
||||
* Returns a boolean value indicating whether the operation succeeded.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function transferFrom(
|
||||
address sender,
|
||||
address recipient,
|
||||
uint256 amount
|
||||
) external returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Emitted when `value` tokens are moved from one account (`from`) to
|
||||
* another (`to`).
|
||||
*
|
||||
* Note that `value` may be zero.
|
||||
*/
|
||||
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
|
||||
* a call to {approve}. `value` is the new allowance.
|
||||
*/
|
||||
event Approval(
|
||||
address indexed owner,
|
||||
address indexed spender,
|
||||
uint256 value
|
||||
);
|
||||
}
|
383
contracts/mainnet/connectors/mstable/main.sol
Normal file
383
contracts/mainnet/connectors/mstable/main.sol
Normal file
|
@ -0,0 +1,383 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
/**
|
||||
* @title mStable SAVE.
|
||||
* @dev Depositing and withdrawing directly to Save
|
||||
*/
|
||||
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
import { IMasset, IBoostedSavingsVault, IFeederPool } from "./interface.sol";
|
||||
|
||||
abstract contract mStableResolver is Events, Helpers {
|
||||
/***************************************
|
||||
CORE
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save via mUSD or bAsset
|
||||
* @notice Deposits token supported by mStable to Save
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _minOut Minimum amount of token to mint/deposit, equal to _amount if mUSD
|
||||
* @param _stake stake token in Vault?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens deposited
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function deposit(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
bool _stake,
|
||||
uint256 _setId,
|
||||
uint256 _getId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_token).balanceOf(address(this))
|
||||
: amount;
|
||||
uint256 mintedAmount;
|
||||
address path;
|
||||
|
||||
// Check if needs to be minted first
|
||||
if (IMasset(mUsdToken).bAssetIndexes(_token) != 0) {
|
||||
// mint first
|
||||
approve(TokenInterface(_token), mUsdToken, amount);
|
||||
mintedAmount = IMasset(mUsdToken).mint(
|
||||
_token,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
path = mUsdToken;
|
||||
} else {
|
||||
require(amount >= _minOut, "mintedAmount < _minOut");
|
||||
mintedAmount = amount;
|
||||
path = imUsdToken;
|
||||
}
|
||||
|
||||
setUint(_setId, mintedAmount);
|
||||
(_eventName, _eventParam) = _deposit(
|
||||
_token,
|
||||
mintedAmount,
|
||||
path,
|
||||
_stake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save via feeder pool
|
||||
* @notice Deposits token, requires _minOut for minting and _path
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address for _token
|
||||
* @param _stake stake token in Vault?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens deposited
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function depositViaSwap(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
bool _stake,
|
||||
uint256 _setId,
|
||||
uint256 _getId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
require(_path != address(0), "Path must be set");
|
||||
require(
|
||||
IMasset(mUsdToken).bAssetIndexes(_token) == 0,
|
||||
"Token is bAsset"
|
||||
);
|
||||
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_token).balanceOf(address(this))
|
||||
: amount;
|
||||
|
||||
approve(TokenInterface(_token), _path, amount);
|
||||
uint256 mintedAmount = IFeederPool(_path).swap(
|
||||
_token,
|
||||
mUsdToken,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, mintedAmount);
|
||||
(_eventName, _eventParam) = _deposit(
|
||||
_token,
|
||||
mintedAmount,
|
||||
_path,
|
||||
_stake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw from Save to mUSD or bAsset
|
||||
* @notice Withdraws from Save Vault to mUSD
|
||||
* @param _token Address of token to withdraw
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _minOut Minimum amount of token to withdraw
|
||||
* @param _unstake from the Vault first?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function withdraw(
|
||||
address _token,
|
||||
uint256 _credits,
|
||||
uint256 _minOut,
|
||||
bool _unstake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 credits = getUint(_getId, _credits);
|
||||
uint256 amountWithdrawn = _withdraw(credits, _unstake);
|
||||
|
||||
// Check if needs to be redeemed
|
||||
if (IMasset(mUsdToken).bAssetIndexes(_token) != 0) {
|
||||
amountWithdrawn = IMasset(mUsdToken).redeem(
|
||||
_token,
|
||||
amountWithdrawn,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else {
|
||||
require(amountWithdrawn >= _minOut, "amountWithdrawn < _minOut");
|
||||
}
|
||||
|
||||
setUint(_setId, amountWithdrawn);
|
||||
_eventName = "LogWithdraw(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(
|
||||
mUsdToken,
|
||||
amountWithdrawn,
|
||||
imUsdToken,
|
||||
_unstake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw from Save via Feeder Pool
|
||||
* @notice Withdraws from Save Vault to asset via Feeder Pool
|
||||
* @param _token bAsset to withdraw to
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address for _token
|
||||
* @param _unstake from the Vault first?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function withdrawViaSwap(
|
||||
address _token,
|
||||
uint256 _credits,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
bool _unstake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
require(_path != address(0), "Path must be set");
|
||||
require(
|
||||
IMasset(mUsdToken).bAssetIndexes(_token) == 0,
|
||||
"Token is bAsset"
|
||||
);
|
||||
|
||||
uint256 credits = getUint(_getId, _credits);
|
||||
|
||||
uint256 amountWithdrawn = _withdraw(credits, _unstake);
|
||||
|
||||
approve(TokenInterface(mUsdToken), _path, amountWithdrawn);
|
||||
uint256 amountRedeemed = IFeederPool(_path).swap(
|
||||
mUsdToken,
|
||||
_token,
|
||||
amountWithdrawn,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, amountRedeemed);
|
||||
|
||||
_eventName = "LogWithdraw(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(_token, amountRedeemed, _path, _unstake);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Claims Rewards
|
||||
* @notice Claims accrued rewards from the Vault
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function claimRewards(uint256 _getId, uint256 _setId)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
address rewardToken = _getRewardTokens();
|
||||
uint256 rewardAmount = _getRewardInternalBal(rewardToken);
|
||||
|
||||
IBoostedSavingsVault(imUsdVault).claimReward();
|
||||
|
||||
uint256 rewardAmountUpdated = _getRewardInternalBal(rewardToken);
|
||||
|
||||
uint256 claimedRewardToken = sub(rewardAmountUpdated, rewardAmount);
|
||||
|
||||
setUint(_setId, claimedRewardToken);
|
||||
|
||||
_eventName = "LogClaimRewards(address,uint256)";
|
||||
_eventParam = abi.encode(rewardToken, claimedRewardToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swap tokens
|
||||
* @notice Swaps tokens via Masset basket
|
||||
* @param _input Token address to swap from
|
||||
* @param _output Token address to swap to
|
||||
* @param _amount Amount of tokens to swap
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens swapped
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_input).balanceOf(address(this))
|
||||
: amount;
|
||||
approve(TokenInterface(_input), mUsdToken, amount);
|
||||
uint256 amountSwapped;
|
||||
|
||||
// Check the assets and swap accordingly
|
||||
if (_output == mUsdToken) {
|
||||
// bAsset to mUSD => mint
|
||||
amountSwapped = IMasset(mUsdToken).mint(
|
||||
_input,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else if (_input == mUsdToken) {
|
||||
// mUSD to bAsset => redeem
|
||||
amountSwapped = IMasset(mUsdToken).redeem(
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else {
|
||||
// bAsset to another bAsset => swap
|
||||
amountSwapped = IMasset(mUsdToken).swap(
|
||||
_input,
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
|
||||
setUint(_setId, amountSwapped);
|
||||
_eventName = "LogSwap(address,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(_input, _output, amount, amountSwapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swap tokens via Feeder Pool
|
||||
* @notice Swaps tokens via Feeder Pool
|
||||
* @param _input Token address to swap from
|
||||
* @param _output Token address to swap to
|
||||
* @param _amount Amount of tokens to swap
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address to use
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens swapped
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function swapViaFeeder(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amountSwapped;
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_input).balanceOf(address(this))
|
||||
: amount;
|
||||
|
||||
approve(TokenInterface(_input), _path, amount);
|
||||
|
||||
// swaps fAsset to mUSD via Feeder Pool
|
||||
// swaps mUSD to fAsset via Feeder Pool
|
||||
amountSwapped = IFeederPool(_path).swap(
|
||||
_input,
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, amountSwapped);
|
||||
|
||||
_eventName = "LogSwap(address,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(_input, _output, amount, amountSwapped);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2mStable is mStableResolver {
|
||||
string public constant name = "mStable-v1.0";
|
||||
}
|
|
@ -20,6 +20,7 @@ abstract contract SushipswapIncentiveResolver is Helpers, Events {
|
|||
* @param amount amount of LP token
|
||||
* @param getId ID to retrieve amount
|
||||
* @param setId ID stores Pool ID
|
||||
* @param data the metadata struct
|
||||
*/
|
||||
function deposit(
|
||||
address token1,
|
||||
|
@ -66,6 +67,7 @@ abstract contract SushipswapIncentiveResolver is Helpers, Events {
|
|||
* @param amount amount of LP token
|
||||
* @param getId ID to retrieve amount
|
||||
* @param setId ID stores Pool ID
|
||||
* @param data the metadata struct
|
||||
*/
|
||||
function withdraw(
|
||||
address token1,
|
||||
|
@ -104,6 +106,7 @@ abstract contract SushipswapIncentiveResolver is Helpers, Events {
|
|||
* @param token1 token1 deposited of LP token
|
||||
* @param token2 token2 deposited LP token
|
||||
* @param setId ID stores Pool ID
|
||||
* @param data the metadata struct
|
||||
*/
|
||||
function harvest(
|
||||
address token1,
|
||||
|
@ -143,6 +146,7 @@ abstract contract SushipswapIncentiveResolver is Helpers, Events {
|
|||
* @param amount amount of LP token
|
||||
* @param getId ID to retrieve amount
|
||||
* @param setId ID stores Pool ID
|
||||
* @param data the metadata struct
|
||||
*/
|
||||
function withdrawAndHarvest(
|
||||
address token1,
|
||||
|
@ -183,6 +187,7 @@ abstract contract SushipswapIncentiveResolver is Helpers, Events {
|
|||
* @param token1 token1 deposited of LP token
|
||||
* @param token2 token2 deposited LP token
|
||||
* @param setId ID stores Pool ID
|
||||
* @param data the metadata struct
|
||||
*/
|
||||
function emergencyWithdraw(
|
||||
address token1,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogSwap(
|
||||
address indexed buyToken,
|
||||
address indexed sellToken,
|
||||
uint256 buyAmt,
|
||||
uint256 sellAmt,
|
||||
uint256 getId,
|
||||
uint256 setId
|
||||
);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../../common/interfaces.sol";
|
||||
import { DSMath } from "../../../common/math.sol";
|
||||
import { Basic } from "../../../common/basic.sol";
|
||||
import { SwapData } from "./interface.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
/**
|
||||
* @dev UniswapV3 Swap Router Address
|
||||
*/
|
||||
address internal constant V3_SWAP_ROUTER_ADDRESS =
|
||||
0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
|
||||
|
||||
/**
|
||||
* @dev UniswapV3 swapHelper
|
||||
* @param swapData - Struct defined in interfaces.sol
|
||||
*/
|
||||
function _swapHelper(SwapData memory swapData)
|
||||
internal
|
||||
returns (uint256 buyAmt)
|
||||
{
|
||||
(uint256 _buyDec, uint256 _sellDec) = getTokensDec(
|
||||
swapData.buyToken,
|
||||
swapData.sellToken
|
||||
);
|
||||
uint256 _sellAmt18 = convertTo18(_sellDec, swapData._sellAmt);
|
||||
uint256 _slippageAmt = convert18ToDec(
|
||||
_buyDec,
|
||||
wmul(swapData.unitAmt, _sellAmt18)
|
||||
);
|
||||
|
||||
uint256 initalBal = getTokenBal(swapData.buyToken);
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
(bool success, ) = V3_SWAP_ROUTER_ADDRESS.call(swapData.callData);
|
||||
if (!success) revert("uniswapV3-swap-failed");
|
||||
|
||||
uint256 finalBal = getTokenBal(swapData.buyToken);
|
||||
|
||||
buyAmt = sub(finalBal, initalBal);
|
||||
require(_slippageAmt <= buyAmt, "Too much slippage");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the swapping data from auto router sdk
|
||||
* @param swapData Struct with multiple swap data defined in interfaces.sol
|
||||
* @param setId Set token amount at this ID in `InstaMemory` Contract.
|
||||
*/
|
||||
function _swap(SwapData memory swapData, uint256 setId)
|
||||
internal
|
||||
returns (SwapData memory)
|
||||
{
|
||||
bool isEthSellToken = address(swapData.sellToken) == ethAddr;
|
||||
bool isEthBuyToken = address(swapData.buyToken) == ethAddr;
|
||||
|
||||
swapData.sellToken = isEthSellToken
|
||||
? TokenInterface(wethAddr)
|
||||
: swapData.sellToken;
|
||||
swapData.buyToken = isEthBuyToken
|
||||
? TokenInterface(wethAddr)
|
||||
: swapData.buyToken;
|
||||
|
||||
convertEthToWeth(isEthSellToken, swapData.sellToken, swapData._sellAmt);
|
||||
|
||||
approve(
|
||||
TokenInterface(swapData.sellToken),
|
||||
V3_SWAP_ROUTER_ADDRESS,
|
||||
swapData._sellAmt
|
||||
);
|
||||
|
||||
swapData._buyAmt = _swapHelper(swapData);
|
||||
|
||||
convertWethToEth(isEthBuyToken, swapData.buyToken, swapData._buyAmt);
|
||||
|
||||
setUint(setId, swapData._buyAmt);
|
||||
|
||||
return swapData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
import { TokenInterface } from "../../../common/interfaces.sol";
|
||||
|
||||
struct SwapData {
|
||||
TokenInterface sellToken;
|
||||
TokenInterface buyToken;
|
||||
uint256 _sellAmt;
|
||||
uint256 _buyAmt;
|
||||
uint256 unitAmt;
|
||||
bytes callData;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
/**
|
||||
* @title UniswapV3_autoRouter.
|
||||
* @dev DEX.
|
||||
*/
|
||||
|
||||
// import files from common directory
|
||||
import { TokenInterface, MemoryInterface } from "../../../common/interfaces.sol";
|
||||
import { Stores } from "../../../common/stores.sol";
|
||||
import { SwapData } from "./interface.sol";
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
|
||||
abstract contract AutoRouter is Helpers, Events {
|
||||
/**
|
||||
* @dev Sell ETH/ERC20_Token using uniswap v3 auto router.
|
||||
* @notice Swap tokens from getting an optimized trade routes
|
||||
* @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
|
||||
* @param sellAmt The amount of the token to sell.
|
||||
* @param unitAmt The amount of buyAmt/sellAmt with slippage.
|
||||
* @param callData Data from Uniswap V3 auto router SDK.
|
||||
* @param setId ID stores the amount of token brought.
|
||||
*/
|
||||
function sell(
|
||||
address buyAddr,
|
||||
address sellAddr,
|
||||
uint256 sellAmt,
|
||||
uint256 unitAmt,
|
||||
bytes calldata callData,
|
||||
uint256 setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
SwapData memory swapData = SwapData({
|
||||
buyToken: TokenInterface(buyAddr),
|
||||
sellToken: TokenInterface(sellAddr),
|
||||
unitAmt: unitAmt,
|
||||
callData: callData,
|
||||
_sellAmt: sellAmt,
|
||||
_buyAmt: 0
|
||||
});
|
||||
|
||||
swapData = _swap(swapData, setId);
|
||||
|
||||
_eventName = "LogSwap(address,address,uint256,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(
|
||||
buyAddr,
|
||||
sellAddr,
|
||||
swapData._buyAmt,
|
||||
swapData._sellAmt,
|
||||
0,
|
||||
setId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2UniswapV3AutoRouterOptimism is AutoRouter {
|
||||
string public name = "UniswapV3-Auto-Router-v1";
|
||||
}
|
23
contracts/polygon/connectors/mstable/events.sol
Normal file
23
contracts/polygon/connectors/mstable/events.sol
Normal file
|
@ -0,0 +1,23 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
contract Events {
|
||||
event LogDeposit(address token, uint256 amount, address path, bool stake);
|
||||
event LogWithdraw(
|
||||
address token,
|
||||
uint256 amount,
|
||||
address path,
|
||||
bool unstake
|
||||
);
|
||||
event LogClaimRewards(
|
||||
address token,
|
||||
uint256 amount,
|
||||
address platformToken,
|
||||
uint256 platformAmount
|
||||
);
|
||||
event LogSwap(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amountIn,
|
||||
uint256 amountOut
|
||||
);
|
||||
}
|
116
contracts/polygon/connectors/mstable/helpers.sol
Normal file
116
contracts/polygon/connectors/mstable/helpers.sol
Normal file
|
@ -0,0 +1,116 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
import { DSMath } from "../../common/math.sol";
|
||||
import { Basic } from "../../common/basic.sol";
|
||||
|
||||
import { ISavingsContractV2, IStakingRewardsWithPlatformToken } from "./interface.sol";
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
address internal constant mUsdToken =
|
||||
0xE840B73E5287865EEc17d250bFb1536704B43B21;
|
||||
address internal constant imUsdToken =
|
||||
0x5290Ad3d83476CA6A2b178Cd9727eE1EF72432af;
|
||||
address internal constant imUsdVault =
|
||||
0x32aBa856Dc5fFd5A56Bcd182b13380e5C855aa29;
|
||||
|
||||
/***************************************
|
||||
Internal
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save from any asset
|
||||
* @notice Called internally from deposit functions
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _path Path to mint mUSD (only needed for Feeder Pool)
|
||||
* @param _stake stake token in Vault?
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function _deposit(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
address _path,
|
||||
bool _stake
|
||||
) internal returns (string memory _eventName, bytes memory _eventParam) {
|
||||
// 1. Deposit mUSD to Save
|
||||
approve(TokenInterface(mUsdToken), imUsdToken, _amount);
|
||||
uint256 credits = ISavingsContractV2(imUsdToken).depositSavings(
|
||||
_amount
|
||||
);
|
||||
if (_stake) {
|
||||
// 2. Stake imUSD to Vault
|
||||
approve(TokenInterface(imUsdToken), imUsdVault, credits);
|
||||
IStakingRewardsWithPlatformToken(imUsdVault).stake(credits);
|
||||
}
|
||||
// 3. Log Events
|
||||
_eventName = "LogDeposit(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(_token, _amount, _path, _stake);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws from Save
|
||||
* @notice Withdraws token supported by mStable from Save
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _unstake unstake from Vault?
|
||||
* @return amountWithdrawn Amount withdrawn in mUSD
|
||||
*/
|
||||
|
||||
function _withdraw(uint256 _credits, bool _unstake)
|
||||
internal
|
||||
returns (uint256 amountWithdrawn)
|
||||
{
|
||||
uint256 credits;
|
||||
// 1. Withdraw from Vault
|
||||
if (_unstake) {
|
||||
credits = _credits == uint256(-1)
|
||||
? TokenInterface(imUsdVault).balanceOf(address(this))
|
||||
: _credits;
|
||||
IStakingRewardsWithPlatformToken(imUsdVault).withdraw(credits);
|
||||
}
|
||||
|
||||
// 2. Withdraw from Save
|
||||
credits = _credits == uint256(-1)
|
||||
? TokenInterface(imUsdToken).balanceOf(address(this))
|
||||
: _credits;
|
||||
approve(TokenInterface(imUsdToken), imUsdVault, _credits);
|
||||
amountWithdrawn = ISavingsContractV2(imUsdToken).redeemCredits(credits);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the reward tokens
|
||||
* @notice Gets the reward tokens from the vault contract
|
||||
* @return rewardToken Address of reward token
|
||||
* @return platformToken Address of platform token
|
||||
*/
|
||||
|
||||
function _getRewardTokens()
|
||||
internal
|
||||
returns (address rewardToken, address platformToken)
|
||||
{
|
||||
rewardToken = IStakingRewardsWithPlatformToken(imUsdVault)
|
||||
.getRewardToken();
|
||||
platformToken = IStakingRewardsWithPlatformToken(imUsdVault)
|
||||
.getPlatformToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the internal balances of the rewardToken and platformToken
|
||||
* @notice Gets current balances of rewardToken and platformToken, used for calculating rewards accrued
|
||||
* @param _rewardToken Address of reward token
|
||||
* @param _platformToken Address of platform token
|
||||
* @return a Amount of reward token
|
||||
* @return b Amount of platform token
|
||||
*/
|
||||
|
||||
function _getRewardInternalBal(address _rewardToken, address _platformToken)
|
||||
internal
|
||||
view
|
||||
returns (uint256 a, uint256 b)
|
||||
{
|
||||
a = TokenInterface(_rewardToken).balanceOf(address(this));
|
||||
b = TokenInterface(_platformToken).balanceOf(address(this));
|
||||
}
|
||||
}
|
234
contracts/polygon/connectors/mstable/interface.sol
Normal file
234
contracts/polygon/connectors/mstable/interface.sol
Normal file
|
@ -0,0 +1,234 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
interface IMasset {
|
||||
// Mint
|
||||
function mint(
|
||||
address _input,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function mintMulti(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function getMintOutput(address _input, uint256 _inputQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 mintOutput);
|
||||
|
||||
function getMintMultiOutput(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities
|
||||
) external view returns (uint256 mintOutput);
|
||||
|
||||
// Swaps
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 swapOutput);
|
||||
|
||||
function getSwapOutput(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity
|
||||
) external view returns (uint256 swapOutput);
|
||||
|
||||
// Redemption
|
||||
function redeem(
|
||||
address _output,
|
||||
uint256 _mAssetQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 outputQuantity);
|
||||
|
||||
function redeemMasset(
|
||||
uint256 _mAssetQuantity,
|
||||
uint256[] calldata _minOutputQuantities,
|
||||
address _recipient
|
||||
) external returns (uint256[] memory outputQuantities);
|
||||
|
||||
function redeemExactBassets(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities,
|
||||
uint256 _maxMassetQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mAssetRedeemed);
|
||||
|
||||
function getRedeemOutput(address _output, uint256 _mAssetQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 bAssetOutput);
|
||||
|
||||
function getRedeemExactBassetsOutput(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities
|
||||
) external view returns (uint256 mAssetAmount);
|
||||
|
||||
// Views
|
||||
// This return an index, could be used to check if it's part of the basket
|
||||
function bAssetIndexes(address) external view returns (uint8);
|
||||
|
||||
function getPrice() external view returns (uint256 price, uint256 k);
|
||||
}
|
||||
|
||||
interface ISavingsContractV2 {
|
||||
function depositInterest(uint256 _amount) external; // V1 & V2
|
||||
|
||||
function depositSavings(uint256 _amount)
|
||||
external
|
||||
returns (uint256 creditsIssued); // V1 & V2
|
||||
|
||||
function depositSavings(uint256 _amount, address _beneficiary)
|
||||
external
|
||||
returns (uint256 creditsIssued); // V2
|
||||
|
||||
function redeemCredits(uint256 _amount)
|
||||
external
|
||||
returns (uint256 underlyingReturned); // V2
|
||||
|
||||
function redeemUnderlying(uint256 _amount)
|
||||
external
|
||||
returns (uint256 creditsBurned); // V2
|
||||
|
||||
function exchangeRate() external view returns (uint256); // V1 & V2
|
||||
|
||||
function balanceOfUnderlying(address _user)
|
||||
external
|
||||
view
|
||||
returns (uint256 balance); // V2
|
||||
|
||||
function underlyingToCredits(uint256 _credits)
|
||||
external
|
||||
view
|
||||
returns (uint256 underlying); // V2
|
||||
|
||||
function creditsToUnderlying(uint256 _underlying)
|
||||
external
|
||||
view
|
||||
returns (uint256 credits); // V2
|
||||
}
|
||||
|
||||
interface IStakingRewardsWithPlatformToken {
|
||||
/**
|
||||
* @dev Stakes a given amount of the StakingToken for the sender
|
||||
* @param _amount Units of StakingToken
|
||||
*/
|
||||
function stake(uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @dev Stakes a given amount of the StakingToken for a given beneficiary
|
||||
* @param _beneficiary Staked tokens are credited to this address
|
||||
* @param _amount Units of StakingToken
|
||||
*/
|
||||
function stake(address _beneficiary, uint256 _amount) external;
|
||||
|
||||
function exit() external;
|
||||
|
||||
/**
|
||||
* @dev Withdraws given stake amount from the pool
|
||||
* @param _amount Units of the staked token to withdraw
|
||||
*/
|
||||
function withdraw(uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @dev Claims outstanding rewards (both platform and native) for the sender.
|
||||
* First updates outstanding reward allocation and then transfers.
|
||||
*/
|
||||
function claimReward() external;
|
||||
|
||||
/**
|
||||
* @dev Claims outstanding rewards for the sender. Only the native
|
||||
* rewards token, and not the platform rewards
|
||||
*/
|
||||
function claimRewardOnly() external;
|
||||
|
||||
function getRewardToken() external returns (address token);
|
||||
|
||||
function getPlatformToken() external returns (address token);
|
||||
}
|
||||
|
||||
interface IFeederPool {
|
||||
// Mint
|
||||
function mint(
|
||||
address _input,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function mintMulti(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mintOutput);
|
||||
|
||||
function getMintOutput(address _input, uint256 _inputQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 mintOutput);
|
||||
|
||||
function getMintMultiOutput(
|
||||
address[] calldata _inputs,
|
||||
uint256[] calldata _inputQuantities
|
||||
) external view returns (uint256 mintOutput);
|
||||
|
||||
// Swaps
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 swapOutput);
|
||||
|
||||
function getSwapOutput(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _inputQuantity
|
||||
) external view returns (uint256 swapOutput);
|
||||
|
||||
// Redemption
|
||||
function redeem(
|
||||
address _output,
|
||||
uint256 _fpTokenQuantity,
|
||||
uint256 _minOutputQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 outputQuantity);
|
||||
|
||||
function redeemProportionately(
|
||||
uint256 _fpTokenQuantity,
|
||||
uint256[] calldata _minOutputQuantities,
|
||||
address _recipient
|
||||
) external returns (uint256[] memory outputQuantities);
|
||||
|
||||
function redeemExactBassets(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities,
|
||||
uint256 _maxMassetQuantity,
|
||||
address _recipient
|
||||
) external returns (uint256 mAssetRedeemed);
|
||||
|
||||
function getRedeemOutput(address _output, uint256 _fpTokenQuantity)
|
||||
external
|
||||
view
|
||||
returns (uint256 bAssetOutput);
|
||||
|
||||
function getRedeemExactBassetsOutput(
|
||||
address[] calldata _outputs,
|
||||
uint256[] calldata _outputQuantities
|
||||
) external view returns (uint256 mAssetAmount);
|
||||
|
||||
// Views
|
||||
function mAsset() external view returns (address);
|
||||
|
||||
function getPrice() external view returns (uint256 price, uint256 k);
|
||||
}
|
398
contracts/polygon/connectors/mstable/main.sol
Normal file
398
contracts/polygon/connectors/mstable/main.sol
Normal file
|
@ -0,0 +1,398 @@
|
|||
pragma solidity ^0.7.6;
|
||||
|
||||
/**
|
||||
* @title mStable SAVE.
|
||||
* @dev Depositing and withdrawing directly to Save
|
||||
*/
|
||||
|
||||
import { Helpers } from "./helpers.sol";
|
||||
import { Events } from "./events.sol";
|
||||
import { IMasset, IStakingRewardsWithPlatformToken, IFeederPool } from "./interface.sol";
|
||||
import { TokenInterface } from "../../common/interfaces.sol";
|
||||
|
||||
abstract contract PmStableResolver is Events, Helpers {
|
||||
/***************************************
|
||||
CORE
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save via mUSD or bAsset
|
||||
* @notice Deposits token supported by mStable to Save
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _minOut Minimum amount of token to mint/deposit, equal to _amount if mUSD
|
||||
* @param _stake stake token in Vault?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens deposited
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function deposit(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
bool _stake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_token).balanceOf(address(this))
|
||||
: amount;
|
||||
uint256 mintedAmount;
|
||||
address path;
|
||||
|
||||
// Check if needs to be minted first
|
||||
if (IMasset(mUsdToken).bAssetIndexes(_token) != 0) {
|
||||
// mint first
|
||||
approve(TokenInterface(_token), mUsdToken, amount);
|
||||
mintedAmount = IMasset(mUsdToken).mint(
|
||||
_token,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
path = mUsdToken;
|
||||
} else {
|
||||
require(amount >= _minOut, "mintedAmount < _minOut");
|
||||
mintedAmount = amount;
|
||||
path = imUsdToken;
|
||||
}
|
||||
|
||||
setUint(_setId, mintedAmount);
|
||||
|
||||
(_eventName, _eventParam) = _deposit(
|
||||
_token,
|
||||
mintedAmount,
|
||||
path,
|
||||
_stake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deposit to Save via feeder pool
|
||||
* @notice Deposits token, requires _minOut for minting and _path
|
||||
* @param _token Address of token to deposit
|
||||
* @param _amount Amount of token to deposit
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address for _token
|
||||
* @param _stake stake token in Vault?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens deposited
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function depositViaSwap(
|
||||
address _token,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
bool _stake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
require(_path != address(0), "Path must be set");
|
||||
require(
|
||||
IMasset(mUsdToken).bAssetIndexes(_token) == 0,
|
||||
"Token is bAsset"
|
||||
);
|
||||
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_token).balanceOf(address(this))
|
||||
: amount;
|
||||
|
||||
approve(TokenInterface(_token), _path, amount);
|
||||
uint256 mintedAmount = IFeederPool(_path).swap(
|
||||
_token,
|
||||
mUsdToken,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, mintedAmount);
|
||||
(_eventName, _eventParam) = _deposit(
|
||||
_token,
|
||||
mintedAmount,
|
||||
_path,
|
||||
_stake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw from Save to mUSD or bAsset
|
||||
* @notice Withdraws from Save Vault to mUSD
|
||||
* @param _token Address of token to withdraw
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _minOut Minimum amount of token to withdraw
|
||||
* @param _unstake from the Vault first?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function withdraw(
|
||||
address _token,
|
||||
uint256 _credits,
|
||||
uint256 _minOut,
|
||||
bool _unstake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 credits = getUint(_getId, _credits);
|
||||
uint256 amountWithdrawn = _withdraw(credits, _unstake);
|
||||
|
||||
// Check if needs to be redeemed
|
||||
if (IMasset(mUsdToken).bAssetIndexes(_token) != 0) {
|
||||
amountWithdrawn = IMasset(mUsdToken).redeem(
|
||||
_token,
|
||||
amountWithdrawn,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else {
|
||||
require(amountWithdrawn >= _minOut, "amountWithdrawn < _minOut");
|
||||
}
|
||||
|
||||
setUint(_setId, amountWithdrawn);
|
||||
_eventName = "LogWithdraw(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(
|
||||
mUsdToken,
|
||||
amountWithdrawn,
|
||||
imUsdToken,
|
||||
_unstake
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw from Save via Feeder Pool
|
||||
* @notice Withdraws from Save Vault to asset via Feeder Pool
|
||||
* @param _token bAsset to withdraw to
|
||||
* @param _credits Credits to withdraw
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address for _token
|
||||
* @param _unstake from the Vault first?
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function withdrawViaSwap(
|
||||
address _token,
|
||||
uint256 _credits,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
bool _unstake,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
require(_path != address(0), "Path must be set");
|
||||
require(
|
||||
IMasset(mUsdToken).bAssetIndexes(_token) == 0,
|
||||
"Token is bAsset"
|
||||
);
|
||||
|
||||
uint256 credits = getUint(_getId, _credits);
|
||||
uint256 amountWithdrawn = _withdraw(credits, _unstake);
|
||||
|
||||
approve(TokenInterface(mUsdToken), _path, amountWithdrawn);
|
||||
uint256 amountRedeemed = IFeederPool(_path).swap(
|
||||
mUsdToken,
|
||||
_token,
|
||||
amountWithdrawn,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, amountRedeemed);
|
||||
_eventName = "LogWithdraw(address,uint256,address,bool)";
|
||||
_eventParam = abi.encode(_token, amountRedeemed, _path, _unstake);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Claims Rewards
|
||||
* @notice Claims accrued rewards from the Vault
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens withdrawn
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function claimRewards(uint256 _getId, uint256 _setId)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
(address rewardToken, address platformToken) = _getRewardTokens();
|
||||
(uint256 rewardAmount, uint256 platformAmount) = _getRewardInternalBal(
|
||||
rewardToken,
|
||||
platformToken
|
||||
);
|
||||
|
||||
IStakingRewardsWithPlatformToken(imUsdVault).claimReward();
|
||||
|
||||
(
|
||||
uint256 rewardAmountUpdated,
|
||||
uint256 platformAmountUpdated
|
||||
) = _getRewardInternalBal(rewardToken, platformToken);
|
||||
|
||||
uint256 claimedRewardToken = sub(rewardAmountUpdated, rewardAmount);
|
||||
|
||||
uint256 claimedPlatformToken = sub(
|
||||
platformAmountUpdated,
|
||||
platformAmount
|
||||
);
|
||||
|
||||
setUint(_setId, claimedRewardToken);
|
||||
_eventName = "LogClaimRewards(address,uint256,address,uint256)";
|
||||
_eventParam = abi.encode(
|
||||
rewardToken,
|
||||
claimedRewardToken,
|
||||
platformToken,
|
||||
claimedPlatformToken
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swap tokens
|
||||
* @notice Swaps tokens via Masset basket
|
||||
* @param _input Token address to swap from
|
||||
* @param _output Token address to swap to
|
||||
* @param _amount Amount of tokens to swap
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens swapped
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_input).balanceOf(address(this))
|
||||
: amount;
|
||||
|
||||
approve(TokenInterface(_input), mUsdToken, amount);
|
||||
uint256 amountSwapped;
|
||||
|
||||
// Check the assets and swap accordingly
|
||||
if (_output == mUsdToken) {
|
||||
// bAsset to mUSD => mint
|
||||
amountSwapped = IMasset(mUsdToken).mint(
|
||||
_input,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else if (_input == mUsdToken) {
|
||||
// mUSD to bAsset => redeem
|
||||
amountSwapped = IMasset(mUsdToken).redeem(
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
} else {
|
||||
// bAsset to another bAsset => swap
|
||||
amountSwapped = IMasset(mUsdToken).swap(
|
||||
_input,
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
|
||||
setUint(_setId, amountSwapped);
|
||||
|
||||
_eventName = "LogSwap(address,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(_input, _output, amount, amountSwapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swap tokens via Feeder Pool
|
||||
* @notice Swaps tokens via Feeder Pool
|
||||
* @param _input Token address to swap from
|
||||
* @param _output Token address to swap to
|
||||
* @param _amount Amount of tokens to swap
|
||||
* @param _minOut Minimum amount of token to mint
|
||||
* @param _path Feeder Pool address to use
|
||||
* @param _getId ID to retrieve amt
|
||||
* @param _setId ID stores the amount of tokens swapped
|
||||
* @return _eventName Event name
|
||||
* @return _eventParam Event parameters
|
||||
*/
|
||||
|
||||
function swapViaFeeder(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _amount,
|
||||
uint256 _minOut,
|
||||
address _path,
|
||||
uint256 _getId,
|
||||
uint256 _setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
uint256 amountSwapped;
|
||||
uint256 amount = getUint(_getId, _amount);
|
||||
amount = amount == uint256(-1)
|
||||
? TokenInterface(_input).balanceOf(address(this))
|
||||
: amount;
|
||||
|
||||
approve(TokenInterface(_input), _path, amount);
|
||||
|
||||
// swaps fAsset to mUSD via Feeder Pool
|
||||
// swaps mUSD to fAsset via Feeder Pool
|
||||
amountSwapped = IFeederPool(_path).swap(
|
||||
_input,
|
||||
_output,
|
||||
amount,
|
||||
_minOut,
|
||||
address(this)
|
||||
);
|
||||
|
||||
setUint(_setId, amountSwapped);
|
||||
|
||||
_eventName = "LogSwap(address,address,uint256,uint256)";
|
||||
_eventParam = abi.encode(_input, _output, amount, amountSwapped);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2PmStable is PmStableResolver {
|
||||
string public constant name = "mStable-Polygon-v1.0";
|
||||
}
|
|
@ -49,6 +49,12 @@
|
|||
"UNISWAP-V3-A": "0x3254Ce8f5b1c82431B8f21Df01918342215825C2",
|
||||
"1INCH-A": "0xA4BF319968986D2352FA1c550D781bBFCCE3FcaB",
|
||||
"WETH-A": "0x6C7256cf7C003dD85683339F75DdE9971f98f2FD"
|
||||
},
|
||||
"fantom" : {
|
||||
"AUTHORITY-A": "0x6CE3e607C808b4f4C26B7F6aDAeB619e49CAbb25",
|
||||
"BASIC-A": "0x9926955e0dd681dc303370c52f4ad0a4dd061687",
|
||||
"BASIC-B": "0x8dA60dee0815a08d16C066b07814b10722fA9306",
|
||||
"BASIC-C": "0x2EadEecf1aB9283a9F76D219CF17eeD4932B8811"
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
|
|
|
@ -24,7 +24,8 @@ const chainIds = {
|
|||
avalanche: 43114,
|
||||
polygon: 137,
|
||||
arbitrum: 42161,
|
||||
optimism: 10
|
||||
optimism: 10,
|
||||
fantom: 250
|
||||
};
|
||||
|
||||
const alchemyApiKey = process.env.ALCHEMY_API_KEY;
|
||||
|
@ -36,6 +37,7 @@ const PRIVATE_KEY = process.env.PRIVATE_KEY;
|
|||
const ETHERSCAN_API = process.env.ETHERSCAN_API_KEY;
|
||||
const POLYGONSCAN_API = process.env.POLYGON_API_KEY;
|
||||
const ARBISCAN_API = process.env.ARBISCAN_API_KEY;
|
||||
const OPTIMISM_API = process.env.OPTIMISM_API_KEY;
|
||||
const SNOWTRACE_API = process.env.SNOWTRACE_API_KEY;
|
||||
const FANTOMSCAN_API = process.env.FANTOM_API_KEY;
|
||||
const mnemonic = process.env.MNEMONIC ?? "test test test test test test test test test test test junk";
|
||||
|
@ -68,6 +70,8 @@ function getScanApiKey(networkType: string) {
|
|||
if (networkType === "avalanche") return SNOWTRACE_API;
|
||||
else if (networkType === "polygon") return POLYGONSCAN_API;
|
||||
else if (networkType === "arbitrum") return ARBISCAN_API;
|
||||
else if (networkType === "fantom") return FANTOMSCAN_API;
|
||||
else if (networkType === "optimism") return OPTIMISM_API;
|
||||
else return ETHERSCAN_API;
|
||||
}
|
||||
|
||||
|
@ -112,7 +116,7 @@ const config: HardhatUserConfig = {
|
|||
avalanche: createConfig("avalanche"),
|
||||
arbitrum: createConfig("arbitrum"),
|
||||
optimism: createConfig("optimism"),
|
||||
fantom: createConfig("optimism")
|
||||
fantom: createConfig("fantom")
|
||||
},
|
||||
paths: {
|
||||
artifacts: "./artifacts",
|
||||
|
|
2400
package-lock.json
generated
2400
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -6,9 +6,9 @@
|
|||
"scripts": {
|
||||
"test": "hardhat run scripts/tests/global-test.ts",
|
||||
"coverage": "./node_modules/.bin/solidity-coverage",
|
||||
"check": "node status-checks/huskyCheck.js",
|
||||
"check-husky": "node status-checks/huskyCheck.js",
|
||||
"deploy": "node scripts/deployConnectorsFromCmd.js",
|
||||
"check": "ts-node status-checks/huskyCheck.ts",
|
||||
"check-husky": "ts-node status-checks/huskyCheck.ts",
|
||||
"deploy": "ts-node scripts/deployConnectorsFromCmd.ts",
|
||||
"test:runner": "hardhat run scripts/tests/run-tests.ts",
|
||||
"typechain": "hardhat typechain",
|
||||
"compile": "hardhat compile",
|
||||
|
|
|
@ -92,7 +92,7 @@ const checkEvents = async (connector: {
|
|||
const eventsPath = `${connector.path}/events.sol`;
|
||||
const mainPath = `${connector.path}/main.sol`;
|
||||
if (connector.events.length) {
|
||||
const eventNames = [];
|
||||
const eventNames:string[] = [];
|
||||
for (let i1 = 0; i1 < connector.mainEvents.length; i1++) {
|
||||
const mainEvent = connector.mainEvents[i1];
|
||||
const name = mainEvent.split("(")[0];
|
||||
|
@ -131,7 +131,7 @@ const checkEvents = async (connector: {
|
|||
}
|
||||
}
|
||||
if (connector.mainEvents.length < connector.events.length) {
|
||||
const deprecatedEvents = connector.events.filter((e) => {
|
||||
const deprecatedEvents = connector.events.filter((e: string) => {
|
||||
let used = false;
|
||||
for (let index = 0; index < eventNames.length; index++) {
|
||||
if (e.split("(")[0].split(" ")[1] === eventNames[index])
|
||||
|
@ -157,7 +157,7 @@ const checkEvents = async (connector: {
|
|||
const getCommments = async (strs: string | any[]) => {
|
||||
try {
|
||||
const comments = [];
|
||||
let type: string;
|
||||
let type: string = '';
|
||||
for (let index = strs.length - 1; index >= 0; index--) {
|
||||
const str = strs[index];
|
||||
if (!type) {
|
||||
|
@ -194,9 +194,9 @@ const parseCode = async (connector: { path: any; code?: any }) => {
|
|||
const eventsFirstLines = [];
|
||||
let func = [];
|
||||
let funcs = [];
|
||||
let event = [];
|
||||
let mainEvents = [];
|
||||
let firstLine: number;
|
||||
let event: string[] = [];
|
||||
let mainEvents: string[] = [];
|
||||
let firstLine: number = -1;
|
||||
let mainEventsLines = [];
|
||||
for (let index = 0; index < strs.length; index++) {
|
||||
const str = strs[index];
|
||||
|
@ -297,7 +297,7 @@ const parseCode = async (connector: { path: any; code?: any }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const checkComments = async (connector) => {
|
||||
const checkComments = async (connector:any) => {
|
||||
try {
|
||||
const errors = [];
|
||||
for (let i1 = 0; i1 < connector.funcs.length; i1++) {
|
||||
|
@ -317,7 +317,7 @@ const checkComments = async (connector) => {
|
|||
}
|
||||
const reqs = ["@dev", "@notice"];
|
||||
for (let i3 = 0; i3 < reqs.length; i3++) {
|
||||
if (!func.comments.some((comment) => comment.startsWith(reqs[i3]))) {
|
||||
if (!func.comments.some((comment: string) => comment.startsWith(reqs[i3]))) {
|
||||
errors.push(
|
||||
`no ${reqs[i3]} for function ${func.name} at ${connector.path}/main.sol:${func.firstLine}`
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@ import fetch from "node-fetch";
|
|||
|
||||
import checks from "./checks";
|
||||
|
||||
const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
|
||||
const [owner, repo] = String(process.env.GITHUB_REPOSITORY).split("/");
|
||||
|
||||
function getCurrentCommitSha() {
|
||||
return cp
|
||||
|
@ -11,6 +11,7 @@ function getCurrentCommitSha() {
|
|||
.toString()
|
||||
.trim();
|
||||
}
|
||||
|
||||
// The SHA provied by GITHUB_SHA is the merge (PR) commit.
|
||||
// We need to get the current commit sha ourself.
|
||||
const sha = getCurrentCommitSha();
|
||||
|
@ -45,7 +46,7 @@ async function setStatus(context: any, state: string, description: string) {
|
|||
try {
|
||||
const response = await callback();
|
||||
await setStatus(name, "success", response);
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
const message = err ? err.message : "Something went wrong";
|
||||
await setStatus(name, "failure", message);
|
||||
}
|
||||
|
|
731
test/mainnet/lido_stETH/abi.json
Normal file
731
test/mainnet/lido_stETH/abi.json
Normal file
|
@ -0,0 +1,731 @@
|
|||
[
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "resume",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [{ "name": "", "type": "string" }],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "stop",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "hasInitialized",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_spender", "type": "address" },
|
||||
{ "name": "_amount", "type": "uint256" }
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "depositContract", "type": "address" },
|
||||
{ "name": "_oracle", "type": "address" },
|
||||
{ "name": "_operators", "type": "address" },
|
||||
{ "name": "_treasury", "type": "address" },
|
||||
{ "name": "_insuranceFund", "type": "address" }
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getInsuranceFund",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_ethAmount", "type": "uint256" }],
|
||||
"name": "getSharesByPooledEth",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_sender", "type": "address" },
|
||||
{ "name": "_recipient", "type": "address" },
|
||||
{ "name": "_amount", "type": "uint256" }
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getOperators",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_script", "type": "bytes" }],
|
||||
"name": "getEVMScriptExecutor",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [{ "name": "", "type": "uint8" }],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getRecoveryVault",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "DEPOSIT_ROLE",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "DEPOSIT_SIZE",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getTotalPooledEther",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "PAUSE_ROLE",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_spender", "type": "address" },
|
||||
{ "name": "_addedValue", "type": "uint256" }
|
||||
],
|
||||
"name": "increaseAllowance",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getTreasury",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "SET_ORACLE",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "isStopped",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "MANAGE_WITHDRAWAL_KEY",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBufferedEther",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "SIGNATURE_LENGTH",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getWithdrawalCredentials",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_account", "type": "address" }],
|
||||
"name": "balanceOf",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getFeeDistribution",
|
||||
"outputs": [
|
||||
{ "name": "treasuryFeeBasisPoints", "type": "uint16" },
|
||||
{ "name": "insuranceFeeBasisPoints", "type": "uint16" },
|
||||
{ "name": "operatorsFeeBasisPoints", "type": "uint16" }
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_sharesAmount", "type": "uint256" }],
|
||||
"name": "getPooledEthByShares",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_oracle", "type": "address" }],
|
||||
"name": "setOracle",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "token", "type": "address" }],
|
||||
"name": "allowRecoverability",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "appId",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getOracle",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getInitializationBlock",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_treasuryFeeBasisPoints", "type": "uint16" },
|
||||
{ "name": "_insuranceFeeBasisPoints", "type": "uint16" },
|
||||
{ "name": "_operatorsFeeBasisPoints", "type": "uint16" }
|
||||
],
|
||||
"name": "setFeeDistribution",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_feeBasisPoints", "type": "uint16" }],
|
||||
"name": "setFee",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_maxDeposits", "type": "uint256" }],
|
||||
"name": "depositBufferedEther",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [{ "name": "", "type": "string" }],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "MANAGE_FEE",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_token", "type": "address" }],
|
||||
"name": "transferToVault",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "SET_TREASURY",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{ "name": "_sender", "type": "address" },
|
||||
{ "name": "_role", "type": "bytes32" },
|
||||
{ "name": "_params", "type": "uint256[]" }
|
||||
],
|
||||
"name": "canPerform",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_referral", "type": "address" }],
|
||||
"name": "submit",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": true,
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "WITHDRAWAL_CREDENTIALS_LENGTH",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_spender", "type": "address" },
|
||||
{ "name": "_subtractedValue", "type": "uint256" }
|
||||
],
|
||||
"name": "decreaseAllowance",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getEVMScriptRegistry",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "PUBKEY_LENGTH",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_amount", "type": "uint256" },
|
||||
{ "name": "_pubkeyHash", "type": "bytes32" }
|
||||
],
|
||||
"name": "withdraw",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_recipient", "type": "address" },
|
||||
{ "name": "_amount", "type": "uint256" }
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getDepositContract",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBeaconStat",
|
||||
"outputs": [
|
||||
{ "name": "depositedValidators", "type": "uint256" },
|
||||
{ "name": "beaconValidators", "type": "uint256" },
|
||||
{ "name": "beaconBalance", "type": "uint256" }
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "BURN_ROLE",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_insuranceFund", "type": "address" }],
|
||||
"name": "setInsuranceFund",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getFee",
|
||||
"outputs": [{ "name": "feeBasisPoints", "type": "uint16" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "SET_INSURANCE_FUND",
|
||||
"outputs": [{ "name": "", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "kernel",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getTotalShares",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{ "name": "_owner", "type": "address" },
|
||||
{ "name": "_spender", "type": "address" }
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "isPetrified",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_withdrawalCredentials", "type": "bytes32" }],
|
||||
"name": "setWithdrawalCredentials",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "depositBufferedEther",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_account", "type": "address" },
|
||||
{ "name": "_sharesAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "burnShares",
|
||||
"outputs": [{ "name": "newTotalShares", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "_treasury", "type": "address" }],
|
||||
"name": "setTreasury",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "name": "_beaconValidators", "type": "uint256" },
|
||||
{ "name": "_beaconBalance", "type": "uint256" }
|
||||
],
|
||||
"name": "pushBeacon",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "_account", "type": "address" }],
|
||||
"name": "sharesOf",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{ "payable": true, "stateMutability": "payable", "type": "fallback" },
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "executor", "type": "address" },
|
||||
{ "indexed": false, "name": "script", "type": "bytes" },
|
||||
{ "indexed": false, "name": "input", "type": "bytes" },
|
||||
{ "indexed": false, "name": "returnData", "type": "bytes" }
|
||||
],
|
||||
"name": "ScriptResult",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "vault", "type": "address" },
|
||||
{ "indexed": true, "name": "token", "type": "address" },
|
||||
{ "indexed": false, "name": "amount", "type": "uint256" }
|
||||
],
|
||||
"name": "RecoverToVault",
|
||||
"type": "event"
|
||||
},
|
||||
{ "anonymous": false, "inputs": [], "name": "Stopped", "type": "event" },
|
||||
{ "anonymous": false, "inputs": [], "name": "Resumed", "type": "event" },
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "from", "type": "address" },
|
||||
{ "indexed": true, "name": "to", "type": "address" },
|
||||
{ "indexed": false, "name": "value", "type": "uint256" }
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "owner", "type": "address" },
|
||||
{ "indexed": true, "name": "spender", "type": "address" },
|
||||
{ "indexed": false, "name": "value", "type": "uint256" }
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [{ "indexed": false, "name": "feeBasisPoints", "type": "uint16" }],
|
||||
"name": "FeeSet",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "name": "treasuryFeeBasisPoints", "type": "uint16" },
|
||||
{ "indexed": false, "name": "insuranceFeeBasisPoints", "type": "uint16" },
|
||||
{ "indexed": false, "name": "operatorsFeeBasisPoints", "type": "uint16" }
|
||||
],
|
||||
"name": "FeeDistributionSet",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [{ "indexed": false, "name": "withdrawalCredentials", "type": "bytes32" }],
|
||||
"name": "WithdrawalCredentialsSet",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "sender", "type": "address" },
|
||||
{ "indexed": false, "name": "amount", "type": "uint256" },
|
||||
{ "indexed": false, "name": "referral", "type": "address" }
|
||||
],
|
||||
"name": "Submitted",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [{ "indexed": false, "name": "amount", "type": "uint256" }],
|
||||
"name": "Unbuffered",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "sender", "type": "address" },
|
||||
{ "indexed": false, "name": "tokenAmount", "type": "uint256" },
|
||||
{ "indexed": false, "name": "sentFromBuffer", "type": "uint256" },
|
||||
{ "indexed": true, "name": "pubkeyHash", "type": "bytes32" },
|
||||
{ "indexed": false, "name": "etherAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "Withdrawal",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
103
test/mainnet/lido_stETH/lidoStEth.test.ts
Normal file
103
test/mainnet/lido_stETH/lidoStEth.test.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import hre from "hardhat";
|
||||
import axios from "axios";
|
||||
import { expect } from "chai";
|
||||
const { ethers } = hre; //check
|
||||
import { BigNumber } from "bignumber.js";
|
||||
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
|
||||
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
|
||||
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
|
||||
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
|
||||
import { addresses } from "../../../scripts/tests/mainnet/addresses";
|
||||
import { abis } from "../../../scripts/constant/abis";
|
||||
import { ConnectV2LidoStEth__factory } from "../../../typechain";
|
||||
import lido_abi from "./abi.json";
|
||||
import type { Signer, Contract } from "ethers";
|
||||
|
||||
describe("LidoStEth", function() {
|
||||
const connectorName = "LidoStEth-test";
|
||||
|
||||
let dsaWallet0: Contract;
|
||||
let wallet0: Signer, wallet1: Signer;
|
||||
let masterSigner: Signer;
|
||||
let instaConnectorsV2: Contract;
|
||||
let connector: Contract;
|
||||
|
||||
before(async () => {
|
||||
// await hre.network.provider.request({
|
||||
// method: "hardhat_reset",
|
||||
// params: [
|
||||
// {
|
||||
// forking: {
|
||||
// // @ts-ignore
|
||||
// jsonRpcUrl: hre.config.networks.hardhat.forking.url,
|
||||
// blockNumber: 14334859
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
[wallet0, wallet1] = await ethers.getSigners();
|
||||
masterSigner = await getMasterSigner();
|
||||
instaConnectorsV2 = await ethers.getContractAt(
|
||||
abis.core.connectorsV2,
|
||||
addresses.core.connectorsV2
|
||||
);
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: ConnectV2LidoStEth__factory,
|
||||
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(!!(await masterSigner.getAddress())).to.be.true;
|
||||
});
|
||||
|
||||
describe("DSA wallet setup", function() {
|
||||
it("Should build DSA v2", async function() {
|
||||
dsaWallet0 = await buildDSAv2(await wallet0.getAddress());
|
||||
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 stake the eth", async function() {
|
||||
const _amt = ethers.utils.parseEther("1");
|
||||
const stETHToken = await ethers.getContractAt(
|
||||
lido_abi,
|
||||
"0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84"
|
||||
);
|
||||
const initialstEthBalance = await stETHToken.balanceOf(dsaWallet0.address)
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "deposit",
|
||||
args: [_amt,0,0]
|
||||
},
|
||||
];
|
||||
const tx = await dsaWallet0
|
||||
.connect(wallet0)
|
||||
.cast(...encodeSpells(spells), await wallet1.getAddress());
|
||||
const receipt = await tx.wait();
|
||||
|
||||
const finalstEthBalance = await stETHToken.balanceOf(dsaWallet0.address)
|
||||
expect(finalstEthBalance).to.be.gt(initialstEthBalance);
|
||||
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(
|
||||
ethers.utils.parseEther("9")
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
160
test/mainnet/mstable/mstable.helpers.ts
Normal file
160
test/mainnet/mstable/mstable.helpers.ts
Normal file
|
@ -0,0 +1,160 @@
|
|||
import hre, { ethers } from "hardhat";
|
||||
import { IERC20Minimal__factory } from "../../../typechain";
|
||||
import { BigNumber as BN } from "ethers";
|
||||
|
||||
export const DEAD_ADDRESS = "0x0000000000000000000000000000000000000001";
|
||||
export const ZERO_ADDRESS = ethers.constants.AddressZero;
|
||||
|
||||
export const DEFAULT_DECIMALS = 18;
|
||||
|
||||
export const ZERO = BN.from(0);
|
||||
export const ONE_MIN = BN.from(60);
|
||||
export const TEN_MINS = BN.from(60 * 10);
|
||||
export const ONE_HOUR = BN.from(60 * 60);
|
||||
export const ONE_DAY = BN.from(60 * 60 * 24);
|
||||
export const FIVE_DAYS = BN.from(60 * 60 * 24 * 5);
|
||||
export const TEN_DAYS = BN.from(60 * 60 * 24 * 10);
|
||||
export const ONE_WEEK = BN.from(60 * 60 * 24 * 7);
|
||||
export const ONE_YEAR = BN.from(60 * 60 * 24 * 365);
|
||||
|
||||
export const connectorName = "MStable";
|
||||
|
||||
interface TokenData {
|
||||
tokenAddress: string;
|
||||
tokenWhaleAddress?: string;
|
||||
feederPool?: string;
|
||||
}
|
||||
|
||||
export const toEther = (amount: BN) => ethers.utils.formatEther(amount);
|
||||
|
||||
export const getToken = (tokenSymbol: string): TokenData => {
|
||||
switch (tokenSymbol) {
|
||||
case "MTA":
|
||||
return {
|
||||
tokenAddress: "0xa3BeD4E1c75D00fa6f4E5E6922DB7261B5E9AcD2"
|
||||
};
|
||||
case "mUSD":
|
||||
return {
|
||||
tokenAddress: "0xe2f2a5c287993345a840db3b0845fbc70f5935a5",
|
||||
tokenWhaleAddress: "0x503828976D22510aad0201ac7EC88293211D23Da"
|
||||
};
|
||||
|
||||
case "DAI":
|
||||
return {
|
||||
tokenAddress: "0x6b175474e89094c44da98b954eedeac495271d0f",
|
||||
tokenWhaleAddress: "0xF977814e90dA44bFA03b6295A0616a897441aceC"
|
||||
};
|
||||
case "USDC":
|
||||
return {
|
||||
tokenAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
||||
};
|
||||
case "imUSD":
|
||||
return {
|
||||
tokenAddress: "0x30647a72dc82d7fbb1123ea74716ab8a317eac19"
|
||||
};
|
||||
|
||||
case "imUSDVault":
|
||||
return {
|
||||
tokenAddress: "0x78BefCa7de27d07DC6e71da295Cc2946681A6c7B"
|
||||
};
|
||||
|
||||
// Feeder Asset
|
||||
case "alUSD":
|
||||
return {
|
||||
tokenAddress: "0xbc6da0fe9ad5f3b0d58160288917aa56653660e9",
|
||||
tokenWhaleAddress: "0x115f95c00e8cf2f5C57250caA555A6B4e50B446b",
|
||||
feederPool: "0x4eaa01974B6594C0Ee62fFd7FEE56CF11E6af936"
|
||||
};
|
||||
|
||||
default:
|
||||
throw new Error(`Token ${tokenSymbol} not supported`);
|
||||
}
|
||||
};
|
||||
|
||||
export const sendToken = async (token: string, amount: any, from: string, to: string): Promise<any> => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [from]
|
||||
});
|
||||
const [signer] = await ethers.getSigners();
|
||||
const sender = hre.ethers.provider.getSigner(from);
|
||||
|
||||
await signer.sendTransaction({
|
||||
to: from,
|
||||
value: ethers.utils.parseEther("1")
|
||||
});
|
||||
|
||||
return await IERC20Minimal__factory.connect(token, sender).transfer(to, amount);
|
||||
};
|
||||
|
||||
export const fundWallet = async (token: string, amount: any, to: string) => {
|
||||
const { tokenAddress, tokenWhaleAddress } = getToken(token);
|
||||
await sendToken(tokenAddress, amount, tokenWhaleAddress!, to);
|
||||
};
|
||||
|
||||
export const calcMinOut = (amount: BN, slippage: number): BN => {
|
||||
const value = simpleToExactAmount(1 - slippage);
|
||||
const minOut = amount.mul(value).div(ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS));
|
||||
return minOut;
|
||||
};
|
||||
|
||||
export const simpleToExactAmount = (amount: number | string | BN, decimals: number | BN = DEFAULT_DECIMALS): BN => {
|
||||
let amountString = amount.toString();
|
||||
const decimalsBN = BN.from(decimals);
|
||||
|
||||
if (decimalsBN.gt(100)) {
|
||||
throw new Error(`Invalid decimals amount`);
|
||||
}
|
||||
|
||||
const scale = BN.from(10).pow(decimals);
|
||||
const scaleString = scale.toString();
|
||||
|
||||
// Is it negative?
|
||||
const negative = amountString.substring(0, 1) === "-";
|
||||
if (negative) {
|
||||
amountString = amountString.substring(1);
|
||||
}
|
||||
|
||||
if (amountString === ".") {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, invalid value`);
|
||||
}
|
||||
|
||||
// Split it into a whole and fractional part
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [whole, fraction, ...rest] = amountString.split(".");
|
||||
if (rest.length > 0) {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, too many decimal points`);
|
||||
}
|
||||
|
||||
if (!whole) {
|
||||
whole = "0";
|
||||
}
|
||||
if (!fraction) {
|
||||
fraction = "0";
|
||||
}
|
||||
|
||||
if (fraction.length > scaleString.length - 1) {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, too many decimal places`);
|
||||
}
|
||||
|
||||
while (fraction.length < scaleString.length - 1) {
|
||||
fraction += "0";
|
||||
}
|
||||
|
||||
const wholeBN = BN.from(whole);
|
||||
const fractionBN = BN.from(fraction);
|
||||
let result = wholeBN.mul(scale).add(fractionBN);
|
||||
|
||||
if (negative) {
|
||||
result = result.mul("-1");
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const advanceBlock = async (): Promise<void> => ethers.provider.send("evm_mine", []);
|
||||
|
||||
export const increaseTime = async (length: BN | number): Promise<void> => {
|
||||
await ethers.provider.send("evm_increaseTime", [BN.from(length).toNumber()]);
|
||||
await advanceBlock();
|
||||
};
|
234
test/mainnet/mstable/mstable.test.ts
Normal file
234
test/mainnet/mstable/mstable.test.ts
Normal file
|
@ -0,0 +1,234 @@
|
|||
import { expect } from "chai";
|
||||
import hre from "hardhat";
|
||||
const { waffle, ethers } = hre;
|
||||
const { provider } = waffle;
|
||||
|
||||
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
|
||||
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
|
||||
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
|
||||
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
|
||||
|
||||
import { addresses } from "../../../scripts/tests/mainnet/addresses";
|
||||
import { abis } from "../../../scripts/constant/abis";
|
||||
import type { Signer, Contract } from "ethers";
|
||||
|
||||
import { ConnectV2mStable__factory, IERC20Minimal__factory, IERC20Minimal } from "../../../typechain";
|
||||
|
||||
import { executeAndAssertDeposit, executeAndAssertSwap, executeAndAssertWithdraw } from "./mstable.utils";
|
||||
|
||||
import {
|
||||
fundWallet,
|
||||
getToken,
|
||||
simpleToExactAmount,
|
||||
DEAD_ADDRESS,
|
||||
calcMinOut,
|
||||
ONE_DAY,
|
||||
increaseTime,
|
||||
connectorName,
|
||||
toEther
|
||||
} from "./mstable.helpers";
|
||||
|
||||
describe("MStable", async () => {
|
||||
let dsaWallet0: Contract;
|
||||
let masterSigner: Signer;
|
||||
let instaConnectorsV2: Contract;
|
||||
let connector: Contract;
|
||||
|
||||
let mtaToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("MTA").tokenAddress, provider);
|
||||
let mUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("mUSD").tokenAddress, provider);
|
||||
let imUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSD").tokenAddress, provider);
|
||||
let imUsdVault: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSDVault").tokenAddress, provider);
|
||||
|
||||
let daiToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("DAI").tokenAddress, provider);
|
||||
let usdcToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("USDC").tokenAddress, provider);
|
||||
let alusdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("alUSD").tokenAddress, provider);
|
||||
|
||||
const wallets = provider.getWallets();
|
||||
const [wallet0, wallet1, wallet2, wallet3] = wallets;
|
||||
|
||||
describe("DSA wallet", async () => {
|
||||
const fundAmount = simpleToExactAmount(10000);
|
||||
|
||||
const setup = async () => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
// @ts-ignore
|
||||
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
|
||||
blockNumber: 13905885
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
masterSigner = await getMasterSigner();
|
||||
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: ConnectV2mStable__factory,
|
||||
signer: masterSigner,
|
||||
connectors: instaConnectorsV2
|
||||
});
|
||||
|
||||
console.log("Connector address", connector.address);
|
||||
|
||||
dsaWallet0 = await buildDSAv2(wallet0.address);
|
||||
|
||||
await wallet0.sendTransaction({
|
||||
to: dsaWallet0.address,
|
||||
value: simpleToExactAmount(10)
|
||||
});
|
||||
|
||||
await fundWallet("mUSD", fundAmount, dsaWallet0.address);
|
||||
await fundWallet("DAI", fundAmount, dsaWallet0.address);
|
||||
await fundWallet("alUSD", fundAmount, dsaWallet0.address);
|
||||
};
|
||||
|
||||
describe("Deploy", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
|
||||
it("Should deploy properly", async () => {
|
||||
expect(instaConnectorsV2.address).to.be.properAddress;
|
||||
expect(connector.address).to.be.properAddress;
|
||||
expect(await masterSigner.getAddress()).to.be.properAddress;
|
||||
|
||||
expect(dsaWallet0.address).to.be.properAddress;
|
||||
});
|
||||
it("Should fund the wallet", async () => {
|
||||
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
|
||||
|
||||
expect(await mUsdToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
expect(await daiToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
expect(await alusdToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
});
|
||||
it("Should not have vault tokens prior", async () => {
|
||||
// No deposits prior
|
||||
expect(await imUsdToken.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
expect(await imUsdVault.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Main SAVE", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
it("Should deposit mUSD to Vault successfully", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = depositAmount;
|
||||
|
||||
await executeAndAssertDeposit("deposit", mUsdToken, depositAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should deposit DAI to Vault successfully (mUSD bAsset)", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = calcMinOut(depositAmount, 0.02);
|
||||
|
||||
await executeAndAssertDeposit("deposit", daiToken, depositAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should deposit alUSD to Vault successfully (via Feeder Pool)", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = calcMinOut(depositAmount, 0.02);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
|
||||
await executeAndAssertDeposit("depositViaSwap", alusdToken, depositAmount, dsaWallet0, wallet0, [
|
||||
minOut,
|
||||
path,
|
||||
true
|
||||
]);
|
||||
});
|
||||
it("Should withdraw from Vault to mUSD", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
|
||||
await executeAndAssertWithdraw("withdraw", mUsdToken, withdrawAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should withdraw from Vault to DAI (mUSD bAsset)", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
|
||||
await executeAndAssertWithdraw("withdraw", mUsdToken, withdrawAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should withdraw from Vault to alUSD (via Feeder Pool)", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
|
||||
await executeAndAssertWithdraw("withdrawViaSwap", alusdToken, withdrawAmount, dsaWallet0, wallet0, [
|
||||
minOut,
|
||||
path,
|
||||
true
|
||||
]);
|
||||
});
|
||||
it("Should claim Rewards", async () => {
|
||||
const mtaBalanceBefore = await mtaToken.balanceOf(dsaWallet0.address);
|
||||
console.log("MTA balance before: ", toEther(mtaBalanceBefore));
|
||||
|
||||
// Wait a bit and let the rewards accumulate
|
||||
await increaseTime(ONE_DAY);
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "claimRewards",
|
||||
args: [0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const mtaBalanceAfter = await mtaToken.balanceOf(dsaWallet0.address);
|
||||
console.log("MTA balance after: ", toEther(mtaBalanceAfter));
|
||||
|
||||
expect(mtaBalanceAfter).to.be.gt(mtaBalanceBefore);
|
||||
});
|
||||
});
|
||||
describe("Main SWAP", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
it("Should swap mUSD to bAsset (redeem)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", mUsdToken, 18, daiToken, 18, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap mUSD to fAsset (via feeder pool)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", mUsdToken, 18, alusdToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap bAsset to mUSD (mint)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", daiToken, 18, mUsdToken, 18, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap bAsset to bAsset (swap)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", daiToken, 18, usdcToken, 6, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap bAsset to fAsset (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", daiToken, 18, alusdToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap fAsset to bAsset (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", alusdToken, 18, daiToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap fAsset to mUSD (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("alUSD").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", alusdToken, 18, mUsdToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
137
test/mainnet/mstable/mstable.utils.ts
Normal file
137
test/mainnet/mstable/mstable.utils.ts
Normal file
|
@ -0,0 +1,137 @@
|
|||
import hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
import {
|
||||
DEFAULT_DECIMALS,
|
||||
DEAD_ADDRESS,
|
||||
toEther,
|
||||
connectorName,
|
||||
simpleToExactAmount,
|
||||
getToken
|
||||
} from "./mstable.helpers";
|
||||
|
||||
import { IERC20Minimal, IERC20Minimal__factory } from "../../../typechain";
|
||||
import { BigNumber, Contract, Wallet } from "ethers";
|
||||
|
||||
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
|
||||
|
||||
const provider = hre.waffle.provider;
|
||||
|
||||
let imUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSD").tokenAddress, provider);
|
||||
let imUsdVault: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSDVault").tokenAddress, provider);
|
||||
|
||||
export const executeAndAssertSwap = async (
|
||||
method: string,
|
||||
tokenFrom: IERC20Minimal,
|
||||
tokenFromDecimals: number,
|
||||
tokenTo: IERC20Minimal,
|
||||
tokenToDecimals: number,
|
||||
swapAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args?: any[]
|
||||
) => {
|
||||
const diffFrom = ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS - tokenFromDecimals);
|
||||
const diffTo = ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS - tokenToDecimals);
|
||||
|
||||
const tokenFromBalanceBefore = (await tokenFrom.balanceOf(dsaWallet0.address)).mul(diffFrom);
|
||||
console.log("Token From balance before: ", toEther(tokenFromBalanceBefore));
|
||||
|
||||
const tokenToBalanceBefore = (await tokenTo.balanceOf(dsaWallet0.address)).mul(diffTo);
|
||||
console.log("Token To balance before: ", toEther(tokenToBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenFrom.address, tokenTo.address, swapAmount, 1, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
console.log("Swapping...", toEther(swapAmount));
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const tokenFromBalanceAfter = (await tokenFrom.balanceOf(dsaWallet0.address)).mul(diffFrom);
|
||||
console.log("Token From balance after: ", toEther(tokenFromBalanceAfter));
|
||||
|
||||
const tokenToBalanceAfter = (await tokenTo.balanceOf(dsaWallet0.address)).mul(diffTo);
|
||||
console.log("Token To balance after: ", toEther(tokenToBalanceAfter));
|
||||
|
||||
expect(tokenFromBalanceAfter).to.be.eq(tokenFromBalanceBefore.sub(swapAmount));
|
||||
expect(tokenToBalanceAfter).to.be.gt(tokenToBalanceBefore);
|
||||
};
|
||||
|
||||
export const executeAndAssertDeposit = async (
|
||||
method: string,
|
||||
tokenFrom: IERC20Minimal,
|
||||
depositAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args?: any[]
|
||||
) => {
|
||||
const FromBalanceBefore = await tokenFrom.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance before: ", toEther(FromBalanceBefore));
|
||||
|
||||
const imUsdVaultBalanceBefore = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance before: ", toEther(imUsdVaultBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenFrom.address, depositAmount, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const FromBalanceAfter = await tokenFrom.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance after: ", toEther(FromBalanceAfter));
|
||||
|
||||
const imUsdBalance = await imUsdToken.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD balance: ", toEther(imUsdBalance));
|
||||
|
||||
const imUsdVaultBalance = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance: ", toEther(imUsdVaultBalance));
|
||||
|
||||
// Should have something in the vault but no imUSD
|
||||
expect(await imUsdToken.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
expect(await imUsdVault.balanceOf(dsaWallet0.address)).to.be.gt(imUsdVaultBalanceBefore);
|
||||
expect(FromBalanceAfter).to.eq(FromBalanceBefore.sub(depositAmount));
|
||||
};
|
||||
|
||||
export const executeAndAssertWithdraw = async (
|
||||
method: string,
|
||||
tokenTo: IERC20Minimal,
|
||||
withdrawAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args: any[]
|
||||
) => {
|
||||
const tokenToBalanceBefore = await tokenTo.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance before: ", toEther(tokenToBalanceBefore));
|
||||
|
||||
const imUsdVaultBalanceBefore = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance before: ", toEther(imUsdVaultBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenTo.address, withdrawAmount, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const imUsdVaultBalanceAfter = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance after: ", toEther(imUsdVaultBalanceAfter));
|
||||
|
||||
const tokenToBalanceAfter = await tokenTo.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance after: ", toEther(tokenToBalanceAfter));
|
||||
|
||||
expect(imUsdVaultBalanceAfter).to.be.eq(imUsdVaultBalanceBefore.sub(withdrawAmount));
|
||||
expect(tokenToBalanceAfter).to.gt(tokenToBalanceBefore);
|
||||
};
|
159
test/polygon/mstable/mstable.helpers.ts
Normal file
159
test/polygon/mstable/mstable.helpers.ts
Normal file
|
@ -0,0 +1,159 @@
|
|||
import hre, { ethers } from "hardhat";
|
||||
import { IERC20Minimal__factory } from "../../../typechain";
|
||||
import { BigNumber as BN } from "ethers";
|
||||
|
||||
export const DEAD_ADDRESS = "0x0000000000000000000000000000000000000001";
|
||||
export const ZERO_ADDRESS = ethers.constants.AddressZero;
|
||||
|
||||
export const DEFAULT_DECIMALS = 18;
|
||||
|
||||
export const ZERO = BN.from(0);
|
||||
export const ONE_MIN = BN.from(60);
|
||||
export const TEN_MINS = BN.from(60 * 10);
|
||||
export const ONE_HOUR = BN.from(60 * 60);
|
||||
export const ONE_DAY = BN.from(60 * 60 * 24);
|
||||
export const FIVE_DAYS = BN.from(60 * 60 * 24 * 5);
|
||||
export const TEN_DAYS = BN.from(60 * 60 * 24 * 10);
|
||||
export const ONE_WEEK = BN.from(60 * 60 * 24 * 7);
|
||||
export const ONE_YEAR = BN.from(60 * 60 * 24 * 365);
|
||||
|
||||
export const connectorName = "MStable";
|
||||
|
||||
interface TokenData {
|
||||
tokenAddress: string;
|
||||
tokenWhaleAddress?: string;
|
||||
feederPool?: string;
|
||||
}
|
||||
|
||||
export const toEther = (amount: BN) => ethers.utils.formatEther(amount);
|
||||
|
||||
export const getToken = (tokenSymbol: string): TokenData => {
|
||||
switch (tokenSymbol) {
|
||||
case "MTA":
|
||||
return {
|
||||
tokenAddress: "0xf501dd45a1198c2e1b5aef5314a68b9006d842e0"
|
||||
};
|
||||
case "mUSD":
|
||||
return {
|
||||
tokenAddress: "0xe840b73e5287865eec17d250bfb1536704b43b21",
|
||||
tokenWhaleAddress: "0x4393b9c542bf79e5235180d6da1915c0f9bc02c3"
|
||||
};
|
||||
|
||||
case "DAI":
|
||||
return {
|
||||
tokenAddress: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063",
|
||||
tokenWhaleAddress: "0x49854708A8c42eEB837A97Dd97D597890CEb1334"
|
||||
};
|
||||
case "USDC":
|
||||
return {
|
||||
tokenAddress: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174"
|
||||
};
|
||||
case "imUSD":
|
||||
return {
|
||||
tokenAddress: "0x5290Ad3d83476CA6A2b178Cd9727eE1EF72432af"
|
||||
};
|
||||
|
||||
case "imUSDVault":
|
||||
return {
|
||||
tokenAddress: "0x32aBa856Dc5fFd5A56Bcd182b13380e5C855aa29"
|
||||
};
|
||||
|
||||
case "FRAX":
|
||||
return {
|
||||
tokenAddress: "0x104592a158490a9228070E0A8e5343B499e125D0",
|
||||
tokenWhaleAddress: "0xAE0f77C239f72da36d4dA20a4bBdaAe4Ca48e03F",
|
||||
feederPool: "0xb30a907084ac8a0d25dddab4e364827406fd09f0"
|
||||
};
|
||||
|
||||
default:
|
||||
throw new Error(`Token ${tokenSymbol} not supported`);
|
||||
}
|
||||
};
|
||||
|
||||
export const sendToken = async (token: string, amount: any, from: string, to: string): Promise<any> => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_impersonateAccount",
|
||||
params: [from]
|
||||
});
|
||||
const [signer] = await ethers.getSigners();
|
||||
const sender = hre.ethers.provider.getSigner(from);
|
||||
|
||||
await signer.sendTransaction({
|
||||
to: from,
|
||||
value: ethers.utils.parseEther("1")
|
||||
});
|
||||
|
||||
return await IERC20Minimal__factory.connect(token, sender).transfer(to, amount);
|
||||
};
|
||||
|
||||
export const fundWallet = async (token: string, amount: any, to: string) => {
|
||||
const { tokenAddress, tokenWhaleAddress } = getToken(token);
|
||||
await sendToken(tokenAddress, amount, tokenWhaleAddress!, to);
|
||||
};
|
||||
|
||||
export const calcMinOut = (amount: BN, slippage: number): BN => {
|
||||
const value = simpleToExactAmount(1 - slippage);
|
||||
const minOut = amount.mul(value).div(ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS));
|
||||
return minOut;
|
||||
};
|
||||
|
||||
export const simpleToExactAmount = (amount: number | string | BN, decimals: number | BN = DEFAULT_DECIMALS): BN => {
|
||||
let amountString = amount.toString();
|
||||
const decimalsBN = BN.from(decimals);
|
||||
|
||||
if (decimalsBN.gt(100)) {
|
||||
throw new Error(`Invalid decimals amount`);
|
||||
}
|
||||
|
||||
const scale = BN.from(10).pow(decimals);
|
||||
const scaleString = scale.toString();
|
||||
|
||||
// Is it negative?
|
||||
const negative = amountString.substring(0, 1) === "-";
|
||||
if (negative) {
|
||||
amountString = amountString.substring(1);
|
||||
}
|
||||
|
||||
if (amountString === ".") {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, invalid value`);
|
||||
}
|
||||
|
||||
// Split it into a whole and fractional part
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [whole, fraction, ...rest] = amountString.split(".");
|
||||
if (rest.length > 0) {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, too many decimal points`);
|
||||
}
|
||||
|
||||
if (!whole) {
|
||||
whole = "0";
|
||||
}
|
||||
if (!fraction) {
|
||||
fraction = "0";
|
||||
}
|
||||
|
||||
if (fraction.length > scaleString.length - 1) {
|
||||
throw new Error(`Error converting number ${amountString} to precise unit, too many decimal places`);
|
||||
}
|
||||
|
||||
while (fraction.length < scaleString.length - 1) {
|
||||
fraction += "0";
|
||||
}
|
||||
|
||||
const wholeBN = BN.from(whole);
|
||||
const fractionBN = BN.from(fraction);
|
||||
let result = wholeBN.mul(scale).add(fractionBN);
|
||||
|
||||
if (negative) {
|
||||
result = result.mul("-1");
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const advanceBlock = async (): Promise<void> => ethers.provider.send("evm_mine", []);
|
||||
|
||||
export const increaseTime = async (length: BN | number): Promise<void> => {
|
||||
await ethers.provider.send("evm_increaseTime", [BN.from(length).toNumber()]);
|
||||
await advanceBlock();
|
||||
};
|
234
test/polygon/mstable/mstable.test.ts
Normal file
234
test/polygon/mstable/mstable.test.ts
Normal file
|
@ -0,0 +1,234 @@
|
|||
import { expect } from "chai";
|
||||
import hre from "hardhat";
|
||||
const { waffle, ethers } = hre;
|
||||
const { provider } = waffle;
|
||||
|
||||
import { deployAndEnableConnector } from "../../../scripts/tests/deployAndEnableConnector";
|
||||
import { buildDSAv2 } from "../../../scripts/tests/buildDSAv2";
|
||||
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
|
||||
import { getMasterSigner } from "../../../scripts/tests/getMasterSigner";
|
||||
|
||||
import { addresses } from "../../../scripts/tests/polygon/addresses";
|
||||
import { abis } from "../../../scripts/constant/abis";
|
||||
import type { Signer, Contract } from "ethers";
|
||||
|
||||
import { ConnectV2PmStable__factory, IERC20Minimal__factory, IERC20Minimal } from "../../../typechain";
|
||||
|
||||
import { executeAndAssertDeposit, executeAndAssertSwap, executeAndAssertWithdraw } from "./mstable.utils";
|
||||
|
||||
import {
|
||||
fundWallet,
|
||||
getToken,
|
||||
simpleToExactAmount,
|
||||
DEAD_ADDRESS,
|
||||
calcMinOut,
|
||||
ONE_DAY,
|
||||
increaseTime,
|
||||
connectorName,
|
||||
toEther
|
||||
} from "./mstable.helpers";
|
||||
|
||||
describe("MStable", async () => {
|
||||
let dsaWallet0: Contract;
|
||||
let masterSigner: Signer;
|
||||
let instaConnectorsV2: Contract;
|
||||
let connector: Contract;
|
||||
|
||||
let mtaToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("MTA").tokenAddress, provider);
|
||||
let mUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("mUSD").tokenAddress, provider);
|
||||
let imUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSD").tokenAddress, provider);
|
||||
let imUsdVault: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSDVault").tokenAddress, provider);
|
||||
|
||||
let daiToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("DAI").tokenAddress, provider);
|
||||
let usdcToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("USDC").tokenAddress, provider);
|
||||
let fraxToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("FRAX").tokenAddress, provider);
|
||||
|
||||
const wallets = provider.getWallets();
|
||||
const [wallet0, wallet1, wallet2, wallet3] = wallets;
|
||||
|
||||
describe("DSA wallet", async () => {
|
||||
const fundAmount = simpleToExactAmount(10000);
|
||||
|
||||
const setup = async () => {
|
||||
await hre.network.provider.request({
|
||||
method: "hardhat_reset",
|
||||
params: [
|
||||
{
|
||||
forking: {
|
||||
// @ts-ignore
|
||||
jsonRpcUrl: hre.config.networks.hardhat.forking.url,
|
||||
blockNumber: 23059414
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
masterSigner = await getMasterSigner();
|
||||
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
|
||||
connector = await deployAndEnableConnector({
|
||||
connectorName,
|
||||
contractArtifact: ConnectV2PmStable__factory,
|
||||
signer: masterSigner,
|
||||
connectors: instaConnectorsV2
|
||||
});
|
||||
|
||||
console.log("Connector address", connector.address);
|
||||
|
||||
dsaWallet0 = await buildDSAv2(wallet0.address);
|
||||
|
||||
await wallet0.sendTransaction({
|
||||
to: dsaWallet0.address,
|
||||
value: simpleToExactAmount(10)
|
||||
});
|
||||
|
||||
await fundWallet("mUSD", fundAmount, dsaWallet0.address);
|
||||
await fundWallet("DAI", fundAmount, dsaWallet0.address);
|
||||
await fundWallet("FRAX", fundAmount, dsaWallet0.address);
|
||||
};
|
||||
|
||||
describe("Deploy", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
|
||||
it("Should deploy properly", async () => {
|
||||
expect(instaConnectorsV2.address).to.be.properAddress;
|
||||
expect(connector.address).to.be.properAddress;
|
||||
expect(await masterSigner.getAddress()).to.be.properAddress;
|
||||
|
||||
expect(dsaWallet0.address).to.be.properAddress;
|
||||
});
|
||||
it("Should fund the wallet", async () => {
|
||||
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10"));
|
||||
|
||||
expect(await mUsdToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
expect(await daiToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
expect(await fraxToken.balanceOf(dsaWallet0.address)).to.be.gte(fundAmount);
|
||||
});
|
||||
it("Should not have vault tokens prior", async () => {
|
||||
// No deposits prior
|
||||
expect(await imUsdToken.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
expect(await imUsdVault.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Main SAVE", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
it("Should deposit mUSD to Vault successfully", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = depositAmount;
|
||||
|
||||
await executeAndAssertDeposit("deposit", mUsdToken, depositAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should deposit DAI to Vault successfully (mUSD bAsset)", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = calcMinOut(depositAmount, 0.02);
|
||||
|
||||
await executeAndAssertDeposit("deposit", daiToken, depositAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should deposit FRAX to Vault successfully (via Feeder Pool)", async () => {
|
||||
const depositAmount = simpleToExactAmount(100);
|
||||
const minOut = calcMinOut(depositAmount, 0.02);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
|
||||
await executeAndAssertDeposit("depositViaSwap", fraxToken, depositAmount, dsaWallet0, wallet0, [
|
||||
minOut,
|
||||
path,
|
||||
true
|
||||
]);
|
||||
});
|
||||
it("Should withdraw from Vault to mUSD", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
|
||||
await executeAndAssertWithdraw("withdraw", mUsdToken, withdrawAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should withdraw from Vault to DAI (mUSD bAsset)", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
|
||||
await executeAndAssertWithdraw("withdraw", mUsdToken, withdrawAmount, dsaWallet0, wallet0, [minOut, true]);
|
||||
});
|
||||
it("Should withdraw from Vault to FRAX (via Feeder Pool)", async () => {
|
||||
const withdrawAmount = simpleToExactAmount(100);
|
||||
const minOut = simpleToExactAmount(1);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
|
||||
await executeAndAssertWithdraw("withdrawViaSwap", fraxToken, withdrawAmount, dsaWallet0, wallet0, [
|
||||
minOut,
|
||||
path,
|
||||
true
|
||||
]);
|
||||
});
|
||||
it("Should claim Rewards", async () => {
|
||||
const mtaBalanceBefore = await mtaToken.balanceOf(dsaWallet0.address);
|
||||
console.log("MTA balance before: ", toEther(mtaBalanceBefore));
|
||||
|
||||
// Wait a bit and let the rewards accumulate
|
||||
await increaseTime(ONE_DAY);
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "claimRewards",
|
||||
args: [0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const mtaBalanceAfter = await mtaToken.balanceOf(dsaWallet0.address);
|
||||
console.log("MTA balance after: ", toEther(mtaBalanceAfter));
|
||||
|
||||
expect(mtaBalanceAfter).to.be.gt(mtaBalanceBefore);
|
||||
});
|
||||
});
|
||||
describe("Main SWAP", async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
});
|
||||
it("Should swap mUSD to bAsset (redeem)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", mUsdToken, 18, daiToken, 18, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap mUSD to fAsset (via feeder pool)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", mUsdToken, 18, fraxToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap bAsset to mUSD (mint)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", daiToken, 18, mUsdToken, 18, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap bAsset to bAsset (swap)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
await executeAndAssertSwap("swap", daiToken, 18, usdcToken, 6, swapAmount, dsaWallet0, wallet0);
|
||||
});
|
||||
it("Should swap bAsset to fAsset (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", daiToken, 18, fraxToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap fAsset to bAsset (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", fraxToken, 18, daiToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
it("Should swap fAsset to mUSD (via feeder)", async () => {
|
||||
const swapAmount = simpleToExactAmount(100);
|
||||
const path = getToken("FRAX").feederPool;
|
||||
await executeAndAssertSwap("swapViaFeeder", fraxToken, 18, mUsdToken, 18, swapAmount, dsaWallet0, wallet0, [
|
||||
path
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
137
test/polygon/mstable/mstable.utils.ts
Normal file
137
test/polygon/mstable/mstable.utils.ts
Normal file
|
@ -0,0 +1,137 @@
|
|||
import hre from "hardhat";
|
||||
import { ethers } from "hardhat";
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
import {
|
||||
DEFAULT_DECIMALS,
|
||||
DEAD_ADDRESS,
|
||||
toEther,
|
||||
connectorName,
|
||||
simpleToExactAmount,
|
||||
getToken
|
||||
} from "./mstable.helpers";
|
||||
|
||||
import { IERC20Minimal, IERC20Minimal__factory } from "../../../typechain";
|
||||
import { BigNumber, Contract, Wallet } from "ethers";
|
||||
|
||||
import { encodeSpells } from "../../../scripts/tests/encodeSpells";
|
||||
|
||||
const provider = hre.waffle.provider;
|
||||
|
||||
let imUsdToken: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSD").tokenAddress, provider);
|
||||
let imUsdVault: IERC20Minimal = IERC20Minimal__factory.connect(getToken("imUSDVault").tokenAddress, provider);
|
||||
|
||||
export const executeAndAssertSwap = async (
|
||||
method: string,
|
||||
tokenFrom: IERC20Minimal,
|
||||
tokenFromDecimals: number,
|
||||
tokenTo: IERC20Minimal,
|
||||
tokenToDecimals: number,
|
||||
swapAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args?: any[]
|
||||
) => {
|
||||
const diffFrom = ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS - tokenFromDecimals);
|
||||
const diffTo = ethers.BigNumber.from(10).pow(DEFAULT_DECIMALS - tokenToDecimals);
|
||||
|
||||
const tokenFromBalanceBefore = (await tokenFrom.balanceOf(dsaWallet0.address)).mul(diffFrom);
|
||||
console.log("Token From balance before: ", toEther(tokenFromBalanceBefore));
|
||||
|
||||
const tokenToBalanceBefore = (await tokenTo.balanceOf(dsaWallet0.address)).mul(diffTo);
|
||||
console.log("Token To balance before: ", toEther(tokenToBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenFrom.address, tokenTo.address, swapAmount, 1, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
console.log("Swapping...", toEther(swapAmount));
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const tokenFromBalanceAfter = (await tokenFrom.balanceOf(dsaWallet0.address)).mul(diffFrom);
|
||||
console.log("Token From balance after: ", toEther(tokenFromBalanceAfter));
|
||||
|
||||
const tokenToBalanceAfter = (await tokenTo.balanceOf(dsaWallet0.address)).mul(diffTo);
|
||||
console.log("Token To balance after: ", toEther(tokenToBalanceAfter));
|
||||
|
||||
expect(tokenFromBalanceAfter).to.be.eq(tokenFromBalanceBefore.sub(swapAmount));
|
||||
expect(tokenToBalanceAfter).to.be.gt(tokenToBalanceBefore);
|
||||
};
|
||||
|
||||
export const executeAndAssertDeposit = async (
|
||||
method: string,
|
||||
tokenFrom: IERC20Minimal,
|
||||
depositAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args?: any[]
|
||||
) => {
|
||||
const FromBalanceBefore = await tokenFrom.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance before: ", toEther(FromBalanceBefore));
|
||||
|
||||
const imUsdVaultBalanceBefore = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance before: ", toEther(imUsdVaultBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenFrom.address, depositAmount, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const FromBalanceAfter = await tokenFrom.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance after: ", toEther(FromBalanceAfter));
|
||||
|
||||
const imUsdBalance = await imUsdToken.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD balance: ", toEther(imUsdBalance));
|
||||
|
||||
const imUsdVaultBalance = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance: ", toEther(imUsdVaultBalance));
|
||||
|
||||
// Should have something in the vault but no imUSD
|
||||
expect(await imUsdToken.balanceOf(dsaWallet0.address)).to.be.eq(0);
|
||||
expect(await imUsdVault.balanceOf(dsaWallet0.address)).to.be.gt(imUsdVaultBalanceBefore);
|
||||
expect(FromBalanceAfter).to.eq(FromBalanceBefore.sub(depositAmount));
|
||||
};
|
||||
|
||||
export const executeAndAssertWithdraw = async (
|
||||
method: string,
|
||||
tokenTo: IERC20Minimal,
|
||||
withdrawAmount: BigNumber,
|
||||
dsaWallet0: Contract,
|
||||
wallet0: Wallet,
|
||||
args: any[]
|
||||
) => {
|
||||
const tokenToBalanceBefore = await tokenTo.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance before: ", toEther(tokenToBalanceBefore));
|
||||
|
||||
const imUsdVaultBalanceBefore = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance before: ", toEther(imUsdVaultBalanceBefore));
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method,
|
||||
args: [tokenTo.address, withdrawAmount, ...(args ? args : []), 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), DEAD_ADDRESS);
|
||||
|
||||
const imUsdVaultBalanceAfter = await imUsdVault.balanceOf(dsaWallet0.address);
|
||||
console.log("imUSD Vault balance after: ", toEther(imUsdVaultBalanceAfter));
|
||||
|
||||
const tokenToBalanceAfter = await tokenTo.balanceOf(dsaWallet0.address);
|
||||
console.log("Balance after: ", toEther(tokenToBalanceAfter));
|
||||
|
||||
expect(imUsdVaultBalanceAfter).to.be.eq(imUsdVaultBalanceBefore.sub(withdrawAmount));
|
||||
expect(tokenToBalanceAfter).to.gt(tokenToBalanceBefore);
|
||||
};
|
|
@ -21,6 +21,7 @@
|
|||
"tasks/**/*",
|
||||
"test/**/*",
|
||||
"typechain/**/*",
|
||||
"types/**/*"
|
||||
"types/**/*",
|
||||
"status-checks/*"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user