feat: set min/max rate

This commit is contained in:
letteldream 2023-08-13 15:18:28 -04:00
parent 8f0cbf710b
commit 00d0da5326
4 changed files with 206 additions and 59 deletions

View File

@ -3,18 +3,36 @@ pragma solidity ^0.7.0;
contract Events { contract Events {
event LogDeposit( event LogDeposit(
address indexed caller, address indexed token,
address indexed owner, uint256 underlyingAmt,
uint256 assets, uint256 minSharesPerToken,
uint256 shares uint256 getId,
uint256 setId
);
event LogMint(
address indexed token,
uint256 shareAmt,
uint256 maxTokenPerShares,
uint256 getId,
uint256 setId
); );
event LogWithdraw( event LogWithdraw(
address indexed caller, address indexed token,
address indexed receiver, uint256 underlyingAmt,
address indexed owner, uint256 maxSharesPerToken,
uint256 assets, address indexed to,
uint256 shares uint256 getId,
uint256 setId
); );
event LogRedeem(
address indexed token,
uint256 shareAmt,
uint256 minTokenPerShares,
address to,
uint256 getId,
uint256 setId
);
} }

View File

@ -22,6 +22,8 @@ interface IERC4626 is IERC20 {
uint256 shares uint256 shares
); );
function decimals() external view returns (uint8);
/** /**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
* *

View File

@ -6,7 +6,7 @@ pragma solidity ^0.7.0;
* @dev Deposit, Mint, Withdraw, & Redeem from ERC4626 DSA. * @dev Deposit, Mint, Withdraw, & Redeem from ERC4626 DSA.
*/ */
// import { IERC4626 } from "@openzeppelin/contracts-latest/interfaces/IERC4626.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC4626 } from "./interface.sol"; import { IERC4626 } from "./interface.sol";
import { TokenInterface } from "../../common/interfaces.sol"; import { TokenInterface } from "../../common/interfaces.sol";
import { DSMath } from "../../common/math.sol"; import { DSMath } from "../../common/math.sol";
@ -18,73 +18,135 @@ abstract contract BasicConnector is Events, DSMath, Basic {
* @dev Deposit underlying asset to ERC4626 Vault. * @dev Deposit underlying asset to ERC4626 Vault.
* @notice Mints vault shares by depositing exactly amount of underlying assets * @notice Mints vault shares by depositing exactly amount of underlying assets
* @param token ERC4626 Token address. * @param token ERC4626 Token address.
* @param amt The amount of the token to deposit. (For max: `uint256(-1)`) * @param underlyingAmt The amount of the underlying asset to deposit. (For max: `uint256(-1)`)
* @param minSharesPerToken The min share rate of deposit
* @param getId ID to retrieve amt. * @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens deposited. * @param setId ID stores the amount of tokens deposited.
*/ */
function deposit( function deposit(
address token, address token,
uint256 amt, uint256 underlyingAmt,
uint256 minSharesPerToken,
uint256 getId, uint256 getId,
uint256 setId uint256 setId
) public returns (string memory _eventName, bytes memory _eventParam) { ) public returns (string memory _eventName, bytes memory _eventParam) {
uint256 _amt = getUint(getId, amt); uint256 _underlyingAmt = getUint(getId, underlyingAmt);
IERC4626 vaultTokenContract = IERC4626(token); IERC4626 vaultTokenContract = IERC4626(token);
address _underlyingToken = vaultTokenContract.asset(); address _underlyingToken = vaultTokenContract.asset();
TokenInterface underlyingTokenContract = TokenInterface(_underlyingToken); uint8 _vaultShareDecimal = vaultTokenContract.decimals();
TokenInterface underlyingTokenContract = TokenInterface(
_underlyingToken
);
_amt = _amt == uint256(-1) ? underlyingTokenContract.balanceOf(address(this)) : _amt; _underlyingAmt = _underlyingAmt == uint256(-1)
? underlyingTokenContract.balanceOf(address(this))
: _underlyingAmt;
approve(underlyingTokenContract, token, _amt); uint256 _minShares = convert18ToDec(
_vaultShareDecimal,
wmul(minSharesPerToken, _underlyingAmt)
);
vaultTokenContract.deposit(_amt, address(this)); uint256 _initalVaultBal = vaultTokenContract.balanceOf(address(this));
setUint(setId, _amt);
_eventName = "LogDeposit(address,uint256,uint256,uint256)"; approve(underlyingTokenContract, token, _underlyingAmt);
_eventParam = abi.encode(token, _amt, getId, setId); vaultTokenContract.deposit(_underlyingAmt, address(this));
uint256 _finalVaultBal = vaultTokenContract.balanceOf(address(this));
require(
_minShares <= sub(_finalVaultBal, _initalVaultBal),
"minShares-exceeds"
);
setUint(setId, _underlyingAmt);
_eventName = "LogDeposit(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
token,
_underlyingAmt,
minSharesPerToken,
getId,
setId
);
} }
/** /**
* @dev Mint underlying asset to ERC4626 Vault. * @dev Mint underlying asset to ERC4626 Vault.
* @notice Mints vault shares by minting exactly amount of underlying assets * @notice Mints vault shares by minting exactly amount of underlying assets
* @param token ERC4626 Token address. * @param token ERC4626 Token address.
* @param amt The amount of the token to mint. (For max: `uint256(-1)`) * @param shareAmt The amount of the share to mint. (For max: `uint256(-1)`)
* @param maxTokenPerShares The max underyling token rate of mint
* @param getId ID to retrieve amt. * @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens minted. * @param setId ID stores the amount of tokens minted.
*/ */
function mint( function mint(
address token, address token,
uint256 amt, uint256 shareAmt,
uint256 maxTokenPerShares,
uint256 getId, uint256 getId,
uint256 setId uint256 setId
) public returns (string memory _eventName, bytes memory _eventParam) { ) public returns (string memory _eventName, bytes memory _eventParam) {
uint256 _amt = getUint(getId, amt); uint256 _shareAmt = getUint(getId, shareAmt);
IERC4626 vaultTokenContract = IERC4626(token); IERC4626 vaultTokenContract = IERC4626(token);
address _underlyingToken = vaultTokenContract.asset(); address _underlyingToken = vaultTokenContract.asset();
TokenInterface underlyingTokenContract = TokenInterface(_underlyingToken); uint8 _vaultShareDecimal = vaultTokenContract.decimals();
TokenInterface underlyingTokenContract = TokenInterface(
_underlyingToken
);
_amt = _amt == uint256(-1) ? underlyingTokenContract.balanceOf(address(this)) : _amt; _shareAmt = _shareAmt == uint256(-1)
? vaultTokenContract.balanceOf(address(this))
: _shareAmt;
uint256 _approveUnderlyingTokenAmount = vaultTokenContract.previewMint(_amt); maxTokenPerShares = convertTo18(
_vaultShareDecimal,
wmul(maxTokenPerShares, _shareAmt)
);
uint256 _approveUnderlyingTokenAmount = vaultTokenContract.previewMint(
_shareAmt
);
uint256 _initalUnderlyingBal = IERC20(_underlyingToken).balanceOf(
address(this)
);
approve(underlyingTokenContract, token, _approveUnderlyingTokenAmount); approve(underlyingTokenContract, token, _approveUnderlyingTokenAmount);
vaultTokenContract.mint(_amt, address(this)); vaultTokenContract.mint(_shareAmt, address(this));
setUint(setId, _amt);
_eventName = "LogDeposit(address,uint256,uint256,uint256)"; uint256 _finalUnderlyingBal = IERC20(_underlyingToken).balanceOf(
_eventParam = abi.encode(token, _amt, getId, setId); address(this)
);
require(
maxTokenPerShares >= sub(_initalUnderlyingBal, _finalUnderlyingBal),
"maxUnderlyingAmt-exceeds"
);
setUint(setId, _shareAmt);
_eventName = "LogMint(address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
token,
_shareAmt,
maxTokenPerShares,
getId,
setId
);
} }
/** /**
* @dev Withdraw underlying asset from ERC4626 Vault. * @dev Withdraw underlying asset from ERC4626 Vault.
* @notice Withdraw vault shares with exactly amount of underlying assets * @notice Withdraw vault shares with exactly amount of underlying assets
* @param token ERC4626 Token address. * @param token ERC4626 Token address.
* @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) * @param underlyingAmt The amount of the token to withdraw. (For max: `uint256(-1)`)
* @param maxSharesPerToken The max share rate of withdrawn amount.
* @param to The address of receiver. * @param to The address of receiver.
* @param getId ID to retrieve amt. * @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens withdrawn. * @param setId ID stores the amount of tokens withdrawn.
@ -92,34 +154,60 @@ abstract contract BasicConnector is Events, DSMath, Basic {
function withdraw( function withdraw(
address token, address token,
uint256 amt, uint256 underlyingAmt,
uint256 maxSharesPerToken,
address payable to, address payable to,
uint256 getId, uint256 getId,
uint256 setId uint256 setId
) public returns (string memory _eventName, bytes memory _eventParam) { ) public returns (string memory _eventName, bytes memory _eventParam) {
uint256 _amt = getUint(getId, amt); uint256 _underlyingAmt = getUint(getId, underlyingAmt);
IERC4626 vaultTokenContract = IERC4626(token); IERC4626 vaultTokenContract = IERC4626(token);
address _underlyingToken = vaultTokenContract.asset(); address _underlyingToken = vaultTokenContract.asset();
TokenInterface underlyingTokenContract = TokenInterface(_underlyingToken); uint8 _vaultShareDecimal = vaultTokenContract.decimals();
TokenInterface underlyingTokenContract = TokenInterface(
_underlyingToken
);
_amt = _amt == uint256(-1) _underlyingAmt = _underlyingAmt == uint256(-1)
? underlyingTokenContract.balanceOf(address(this)) ? underlyingTokenContract.balanceOf(address(this))
: _amt; : _underlyingAmt;
vaultTokenContract.withdraw(_amt, to, address(this)); uint256 _maxShares = convert18ToDec(
setUint(setId, _amt); _vaultShareDecimal,
wmul(maxSharesPerToken, _underlyingAmt)
);
_eventName = "LogWithdraw(address,uint256,address,uint256,uint256)"; uint256 _initalVaultBal = vaultTokenContract.balanceOf(address(this));
_eventParam = abi.encode(token, _amt, to, getId, setId);
vaultTokenContract.withdraw(_underlyingAmt, to, address(this));
uint256 _finalVaultBal = vaultTokenContract.balanceOf(address(this));
require(
_maxShares >= sub(_finalVaultBal, _initalVaultBal),
"minShares-exceeds"
);
setUint(setId, _underlyingAmt);
_eventName = "LogWithdraw(address,uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
token,
_underlyingAmt,
maxSharesPerToken,
to,
getId,
setId
);
} }
/** /**
* @dev Redeem underlying asset from ERC4626 Vault. * @dev Redeem underlying asset from ERC4626 Vault.
* @notice Redeem vault shares with exactly amount of underlying assets * @notice Redeem vault shares with exactly amount of underlying assets
* @param token ERC4626 Token address. * @param token ERC4626 Token address.
* @param amt The amount of the token to redeem. (For max: `uint256(-1)`) * @param shareAmt The amount of the token to redeem. (For max: `uint256(-1)`)
* @param minTokenPerShares The min underlying token rate of withdraw.
* @param to The address of receiver. * @param to The address of receiver.
* @param getId ID to retrieve amt. * @param getId ID to retrieve amt.
* @param setId ID stores the amount of tokens redeem. * @param setId ID stores the amount of tokens redeem.
@ -127,26 +215,56 @@ abstract contract BasicConnector is Events, DSMath, Basic {
function redeem( function redeem(
address token, address token,
uint256 amt, uint256 shareAmt,
uint256 minTokenPerShares,
address payable to, address payable to,
uint256 getId, uint256 getId,
uint256 setId uint256 setId
) public returns (string memory _eventName, bytes memory _eventParam) { ) public returns (string memory _eventName, bytes memory _eventParam) {
uint256 _amt = getUint(getId, amt); uint256 _shareAmt = getUint(getId, shareAmt);
IERC4626 vaultTokenContract = IERC4626(token); IERC4626 vaultTokenContract = IERC4626(token);
address _underlyingToken = vaultTokenContract.asset(); address _underlyingToken = vaultTokenContract.asset();
TokenInterface underlyingTokenContract = TokenInterface(_underlyingToken); uint8 _vaultShareDecimal = vaultTokenContract.decimals();
TokenInterface underlyingTokenContract = TokenInterface(
_underlyingToken
);
_amt = _amt == uint256(-1) _shareAmt = _shareAmt == uint256(-1)
? underlyingTokenContract.balanceOf(address(this)) ? vaultTokenContract.balanceOf(address(this))
: _amt; : _shareAmt;
vaultTokenContract.redeem(_amt, to, address(this)); uint256 _minUnderlyingAmt = convertTo18(
setUint(setId, _amt); _vaultShareDecimal,
wmul(minTokenPerShares, _shareAmt)
);
// uint256 _minUnderlyingAmt = (shareAmt * minTokenPerShares) / 10**18;
_eventName = "LogWithdraw(address,uint256,address,uint256,uint256)"; uint256 _initalUnderlyingBal = IERC20(_underlyingToken).balanceOf(
_eventParam = abi.encode(token, _amt, to, getId, setId); address(this)
);
vaultTokenContract.redeem(_shareAmt, to, address(this));
uint256 _finalUnderlyingBal = IERC20(_underlyingToken).balanceOf(
address(this)
);
require(
_minUnderlyingAmt <= sub(_finalUnderlyingBal, _initalUnderlyingBal),
"minTokens-exceeds"
);
setUint(setId, _shareAmt);
_eventName = "LogRedeem(address,uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
token,
_shareAmt,
minTokenPerShares,
to,
getId,
setId
);
} }
} }

View File

@ -42,8 +42,8 @@ describe("BASIC-D", function () {
{ {
forking: { forking: {
// @ts-ignore // @ts-ignore
jsonRpcUrl: hre.config.networks.hardhat.forking.url jsonRpcUrl: hre.config.networks.hardhat.forking?.url,
// blockNumber: 12796965 blockNumber: 17907926
} }
} }
] ]
@ -122,21 +122,30 @@ describe("BASIC-D", function () {
// const maxMint = await erc4626Contract.maxMint(); // const maxMint = await erc4626Contract.maxMint();
// console.log("maxMint :>> ", maxMint); // console.log("maxMint :>> ", maxMint);
const minSharesPerToken = ethers.utils.parseUnits("0.8");
const beforbalance = await erc4626Contract.balanceOf(dsaWallet0.address);
console.log("beforbalance :>> ", beforbalance);
const spells = [ const spells = [
// {
// connector: connectorName,
// method: "deposit",
// args: [sDAIaddress, new BigNumber(1).toString(), 0, 0]
// },
{ {
connector: connectorName, connector: connectorName,
method: "deposit", method: "deposit",
args: [sDAIaddress, new BigNumber(1).toString(), 0, 0] args: [sDAIaddress, assets, minSharesPerToken, 0, 0]
},
{
connector: connectorName,
method: "deposit",
args: [sDAIaddress, assets, 0, 0]
} }
]; ];
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address); const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet0.address);
const receipt = await tx.wait(); const receipt = await tx.wait();
const afterbalance = await erc4626Contract.balanceOf(dsaWallet0.address);
console.log("afterbalance :>> ", afterbalance);
}); });
it("should mint asset to ERC4626", async () => { it("should mint asset to ERC4626", async () => {
const daiBalance = await daiContract.balanceOf(dsaWallet0.address); const daiBalance = await daiContract.balanceOf(dsaWallet0.address);