From a057263b3f35e65950897699f470815d77f0fdc0 Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Wed, 29 Sep 2021 18:16:30 +0400 Subject: [PATCH 1/6] Add Benqi connectors on Avalanche --- contracts/avalanche/common/basic.sol | 54 +++ contracts/avalanche/common/interfaces.sol | 27 ++ contracts/avalanche/common/math.sol | 50 ++ contracts/avalanche/common/stores.sol | 42 ++ contracts/avalanche/connectors/Qi/events.sol | 6 + contracts/avalanche/connectors/Qi/helpers.sol | 53 +++ .../avalanche/connectors/Qi/interface.sol | 17 + contracts/avalanche/connectors/Qi/main.sol | 103 ++++ .../avalanche/connectors/benqi/events.sol | 62 +++ .../avalanche/connectors/benqi/helpers.sol | 35 ++ .../avalanche/connectors/benqi/interface.sol | 36 ++ contracts/avalanche/connectors/benqi/main.sol | 441 ++++++++++++++++++ contracts/avalanche/mapping/benqi.sol | 137 ++++++ contracts/avalanche/static/basic.sol | 77 +++ 14 files changed, 1140 insertions(+) create mode 100644 contracts/avalanche/common/basic.sol create mode 100644 contracts/avalanche/common/interfaces.sol create mode 100644 contracts/avalanche/common/math.sol create mode 100644 contracts/avalanche/common/stores.sol create mode 100644 contracts/avalanche/connectors/Qi/events.sol create mode 100644 contracts/avalanche/connectors/Qi/helpers.sol create mode 100644 contracts/avalanche/connectors/Qi/interface.sol create mode 100644 contracts/avalanche/connectors/Qi/main.sol create mode 100644 contracts/avalanche/connectors/benqi/events.sol create mode 100644 contracts/avalanche/connectors/benqi/helpers.sol create mode 100644 contracts/avalanche/connectors/benqi/interface.sol create mode 100644 contracts/avalanche/connectors/benqi/main.sol create mode 100644 contracts/avalanche/mapping/benqi.sol create mode 100644 contracts/avalanche/static/basic.sol diff --git a/contracts/avalanche/common/basic.sol b/contracts/avalanche/common/basic.sol new file mode 100644 index 00000000..ff2c8fe9 --- /dev/null +++ b/contracts/avalanche/common/basic.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.7.0; + +import { TokenInterface } from "./interfaces.sol"; +import { Stores } from "./stores.sol"; +import { DSMath } from "./math.sol"; + +abstract contract Basic is DSMath, Stores { + + function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = (_amt / 10 ** (18 - _dec)); + } + + function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) { + amt = mul(_amt, 10 ** (18 - _dec)); + } + + function getTokenBal(TokenInterface token) internal view returns(uint _amt) { + _amt = address(token) == avaxAddr ? address(this).balance : token.balanceOf(address(this)); + } + + function getTokensDec(TokenInterface buyAddr, TokenInterface sellAddr) internal view returns(uint buyDec, uint sellDec) { + buyDec = address(buyAddr) == avaxAddr ? 18 : buyAddr.decimals(); + sellDec = address(sellAddr) == avaxAddr ? 18 : sellAddr.decimals(); + } + + function encodeEvent(string memory eventName, bytes memory eventParam) internal pure returns (bytes memory) { + return abi.encode(eventName, eventParam); + } + + function approve(TokenInterface token, address spender, uint256 amount) internal { + try token.approve(spender, amount) { + + } catch { + token.approve(spender, 0); + token.approve(spender, amount); + } + } + + function changeAvaxAddress(address buy, address sell) internal pure returns(TokenInterface _buy, TokenInterface _sell){ + _buy = buy == avaxAddr ? TokenInterface(wavaxAddr) : TokenInterface(buy); + _sell = sell == avaxAddr ? TokenInterface(wavaxAddr) : TokenInterface(sell); + } + + function convertAvaxToWavax(bool isAvax, TokenInterface token, uint amount) internal { + if(isAvax) token.deposit{value: amount}(); + } + + function convertWavaxToAvax(bool isAvax, TokenInterface token, uint amount) internal { + if(isAvax) { + approve(token, address(token), amount); + token.withdraw(amount); + } + } +} diff --git a/contracts/avalanche/common/interfaces.sol b/contracts/avalanche/common/interfaces.sol new file mode 100644 index 00000000..f9d704af --- /dev/null +++ b/contracts/avalanche/common/interfaces.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.7.0; + +interface TokenInterface { + function approve(address, uint256) external; + function transfer(address, uint) external; + function transferFrom(address, address, uint) external; + function deposit() external payable; + function withdraw(uint) external; + function balanceOf(address) external view returns (uint); + function decimals() external view returns (uint); +} + +interface MemoryInterface { + function getUint(uint id) external returns (uint num); + function setUint(uint id, uint val) external; +} + +interface InstaMapping { + function qiTokenMapping(address) external view returns (address); + function gemJoinMapping(bytes32) external view returns (address); +} + +interface AccountInterface { + function enable(address) external; + function disable(address) external; + function isAuth(address) external view returns (bool); +} diff --git a/contracts/avalanche/common/math.sol b/contracts/avalanche/common/math.sol new file mode 100644 index 00000000..f6e2e6cd --- /dev/null +++ b/contracts/avalanche/common/math.sol @@ -0,0 +1,50 @@ +pragma solidity ^0.7.0; + +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + +contract DSMath { + uint constant WAD = 10 ** 18; + uint constant RAY = 10 ** 27; + + function add(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(x, y); + } + + function sub(uint x, uint y) internal virtual pure returns (uint z) { + z = SafeMath.sub(x, y); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.mul(x, y); + } + + function div(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.div(x, y); + } + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y; + } + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY; + } + + function toInt(uint x) internal pure returns (int y) { + y = int(x); + require(y >= 0, "int-overflow"); + } + + function toRad(uint wad) internal pure returns (uint rad) { + rad = mul(wad, 10 ** 27); + } + +} diff --git a/contracts/avalanche/common/stores.sol b/contracts/avalanche/common/stores.sol new file mode 100644 index 00000000..783a94a3 --- /dev/null +++ b/contracts/avalanche/common/stores.sol @@ -0,0 +1,42 @@ +pragma solidity ^0.7.0; + +import { MemoryInterface, InstaMapping } from "./interfaces.sol"; + + +abstract contract Stores { + + /** + * @dev Return avax address + */ + address constant internal avaxAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + /** + * @dev Return Wrapped AVAX address + */ + address constant internal wavaxAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + /** + * @dev Return memory variable address + */ + MemoryInterface constant internal instaMemory = MemoryInterface(0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F); + + /** + * @dev Return InstaDApp Mapping Addresses + */ + InstaMapping constant internal instaMapping = InstaMapping(0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88); + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : instaMemory.getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) virtual internal { + if (setId != 0) instaMemory.setUint(setId, val); + } + +} diff --git a/contracts/avalanche/connectors/Qi/events.sol b/contracts/avalanche/connectors/Qi/events.sol new file mode 100644 index 00000000..5c6a0f6f --- /dev/null +++ b/contracts/avalanche/connectors/Qi/events.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.7.0; + +contract Events { + event LogClaimedReward(uint256 rewardAmt, uint256 setId); + event LogDelegate(address delegatee); +} diff --git a/contracts/avalanche/connectors/Qi/helpers.sol b/contracts/avalanche/connectors/Qi/helpers.sol new file mode 100644 index 00000000..b0a57a94 --- /dev/null +++ b/contracts/avalanche/connectors/Qi/helpers.sol @@ -0,0 +1,53 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +import { DSMath } from "../../common/math.sol"; +import { Basic } from "../../common/basic.sol"; +import { ComptrollerInterface, QiInterface, BenqiMappingInterface } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Benqi Comptroller + */ + ComptrollerInterface internal constant troller = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); + + /** + * @dev Reward Token + */ + QiInterface internal constant benqiToken = QiInterface(0xc00e94Cb662C3520282E6f5717214004A7f26888); + + /** + * @dev Benqi Mapping + */ + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); + + function getMergedQiTokens( + string[] calldata supplyIds, + string[] calldata borrowIds + ) internal view returns (address[] memory qitokens, bool isBorrow, bool isSupply) { + uint _supplyLen = supplyIds.length; + uint _borrowLen = borrowIds.length; + uint _totalLen = add(_supplyLen, _borrowLen); + qitokens = new address[](_totalLen); + + if(_supplyLen > 0) { + isSupply = true; + for (uint i = 0; i < _supplyLen; i++) { + (address token, address qiToken) = qiMapping.getMapping(supplyIds[i]); + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + qitokens[i] = qiToken; + } + } + + if(_borrowLen > 0) { + isBorrow = true; + for (uint i = 0; i < _borrowLen; i++) { + (address token, address qiToken) = qiMapping.getMapping(borrowIds[i]); + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + qitokens[_supplyLen + i] = qiToken; + } + } + } +} \ No newline at end of file diff --git a/contracts/avalanche/connectors/Qi/interface.sol b/contracts/avalanche/connectors/Qi/interface.sol new file mode 100644 index 00000000..0df5011e --- /dev/null +++ b/contracts/avalanche/connectors/Qi/interface.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.7.0; + +interface ComptrollerInterface { + function claimReward(address holder) external; + function claimReward(address holder, address[] calldata) external; + function claimReward(address[] calldata holders, address[] calldata qiTokens, bool borrowers, bool suppliers) external; +} + +interface QiInterface { + function delegate(address delegatee) external; + function delegates(address) external view returns(address); +} + +interface BenqiMappingInterface { + function qiTokenMapping(string calldata tokenId) external view returns (address); + function getMapping(string calldata tokenId) external view returns (address, address); +} \ No newline at end of file diff --git a/contracts/avalanche/connectors/Qi/main.sol b/contracts/avalanche/connectors/Qi/main.sol new file mode 100644 index 00000000..ebc0cf96 --- /dev/null +++ b/contracts/avalanche/connectors/Qi/main.sol @@ -0,0 +1,103 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title Reward. + * @dev Claim Reward. + */ +import { TokenInterface } from "../../common/interfaces.sol"; +import { Stores } from "../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; + +abstract contract BenqiResolver is Events, Helpers { + + /** + * @dev Claim Accrued Reward Token. + * @notice Claim Accrued Reward Token. + * @param setId ID stores the amount of Reward claimed. + */ + function ClaimReward(uint256 setId) external payable returns (string memory _eventName, bytes memory _eventParam) { + TokenInterface _benqiToken = TokenInterface(address(benqiToken)); + uint intialBal = _benqiToken.balanceOf(address(this)); + troller.claimReward(address(this)); + uint finalBal = _benqiToken.balanceOf(address(this)); + uint amt = sub(finalBal, intialBal); + + setUint(setId, amt); + + _eventName = "LogClaimedReward(uint256,uint256)"; + _eventParam = abi.encode(amt, setId); + } + + /** + * @dev Claim Accrued Reward Token. + * @notice Claim Accrued Reward Token. + * @param tokenIds Array of supplied and borrowed token IDs. + * @param setId ID stores the amount of Reward claimed. + */ + function ClaimRewardTwo(string[] calldata tokenIds, uint256 setId) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _len = tokenIds.length; + address[] memory qitokens = new address[](_len); + for (uint i = 0; i < _len; i++) { + (address token, address qiToken) = qiMapping.getMapping(tokenIds[i]); + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + qitokens[i] = qiToken; + } + + TokenInterface _benqiToken = TokenInterface(address(benqiToken)); + uint intialBal = _benqiToken.balanceOf(address(this)); + troller.claimReward(address(this), qitokens); + uint finalBal = _benqiToken.balanceOf(address(this)); + uint amt = sub(finalBal, intialBal); + + setUint(setId, amt); + + _eventName = "LogClaimedReward(uint256,uint256)"; + _eventParam = abi.encode(amt, setId); + } + + /** + * @dev Claim Accrued Reward Token. + * @notice Claim Accrued Reward Token. + * @param supplyTokenIds Array of supplied tokenIds. + * @param borrowTokenIds Array of borrowed tokenIds. + * @param setId ID stores the amount of Reward claimed. + */ + function ClaimRewardThree(string[] calldata supplyTokenIds, string[] calldata borrowTokenIds, uint256 setId) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address[] memory qitokens, bool isBorrow, bool isSupply) = getMergedQiTokens(supplyTokenIds, borrowTokenIds); + + address[] memory holders = new address[](1); + holders[0] = address(this); + + TokenInterface _benqiToken = TokenInterface(address(benqiToken)); + uint intialBal = _benqiToken.balanceOf(address(this)); + troller.claimReward(holders, qitokens, isBorrow, isSupply); + uint finalBal = _benqiToken.balanceOf(address(this)); + uint amt = sub(finalBal, intialBal); + + setUint(setId, amt); + + _eventName = "LogClaimedReward(uint256,uint256)"; + _eventParam = abi.encode(amt, setId); + } + + /** + * @dev Delegate votes. + * @notice Delegate votes. + * @param delegatee The address to delegate the votes to. + */ + function delegate(address delegatee) external payable returns (string memory _eventName, bytes memory _eventParam) { + require(benqiToken.delegates(address(this)) != delegatee, "Already delegated to same delegatee."); + + benqiToken.delegate(delegatee); + + _eventName = "LogDelegate(address)"; + _eventParam = abi.encode(delegatee); + } +} + +contract ConnectBenqi is BenqiResolver { + string public constant name = "Benqi-v1.0"; +} diff --git a/contracts/avalanche/connectors/benqi/events.sol b/contracts/avalanche/connectors/benqi/events.sol new file mode 100644 index 00000000..8d4295e1 --- /dev/null +++ b/contracts/avalanche/connectors/benqi/events.sol @@ -0,0 +1,62 @@ +pragma solidity ^0.7.0; + +contract Events { + event LogDeposit( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogWithdraw( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogBorrow( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogPayback( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogDepositQiToken( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 qiTokenAmt, + uint256 getId, + uint256 setId + ); + + event LogWithdrawQiToken( + address indexed token, + address qiToken, + uint256 tokenAmt, + uint256 qiTokenAmt, + uint256 getId, + uint256 setId + ); + + event LogLiquidate( + address indexed borrower, + address indexed tokenToPay, + address indexed tokenInReturn, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); +} diff --git a/contracts/avalanche/connectors/benqi/helpers.sol b/contracts/avalanche/connectors/benqi/helpers.sol new file mode 100644 index 00000000..bc5b260f --- /dev/null +++ b/contracts/avalanche/connectors/benqi/helpers.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../common/math.sol"; +import { Basic } from "../../common/basic.sol"; +import { ComptrollerInterface, BenqiMappingInterface } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Benqi Comptroller + */ + ComptrollerInterface internal constant troller = ComptrollerInterface(0x486Af39519B4Dc9a7fCcd318217352830E8AD9b4); + + /** + * @dev Benqi Mapping + */ + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); + + /** + * @dev enter benqi market + */ + function enterMarket(address qiToken) internal { + address[] memory markets = troller.getAssetsIn(address(this)); + bool isEntered = false; + for (uint i = 0; i < markets.length; i++) { + if (markets[i] == qiToken) { + isEntered = true; + } + } + if (!isEntered) { + address[] memory toEnter = new address[](1); + toEnter[0] = qiToken; + troller.enterMarkets(toEnter); + } + } +} diff --git a/contracts/avalanche/connectors/benqi/interface.sol b/contracts/avalanche/connectors/benqi/interface.sol new file mode 100644 index 00000000..26709a05 --- /dev/null +++ b/contracts/avalanche/connectors/benqi/interface.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.7.0; + +interface QiTokenInterface { + function mint(uint mintAmount) external returns (uint); + function redeem(uint redeemTokens) external returns (uint); + function borrow(uint borrowAmount) external returns (uint); + function repayBorrow(uint repayAmount) external returns (uint); + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ARC20 + function liquidateBorrow(address borrower, uint repayAmount, address qiTokenCollateral) external returns (uint); + + function borrowBalanceCurrent(address account) external returns (uint); + function redeemUnderlying(uint redeemAmount) external returns (uint); + function exchangeRateCurrent() external returns (uint); + + function balanceOf(address owner) external view returns (uint256 balance); +} + +interface QiAVAXInterface { + function mint() external payable; + function repayBorrow() external payable; + function repayBorrowBehalf(address borrower) external payable; + function liquidateBorrow(address borrower, address qiTokenCollateral) external payable; +} + +interface ComptrollerInterface { + function enterMarkets(address[] calldata qiTokens) external returns (uint[] memory); + function exitMarket(address qiTokenAddress) external returns (uint); + function getAssetsIn(address account) external view returns (address[] memory); + function getAccountLiquidity(address account) external view returns (uint, uint, uint); + function claimReward(address) external; +} + +interface BenqiMappingInterface { + function qiTokenMapping(string calldata tokenId) external view returns (address); + function getMapping(string calldata tokenId) external view returns (address, address); +} \ No newline at end of file diff --git a/contracts/avalanche/connectors/benqi/main.sol b/contracts/avalanche/connectors/benqi/main.sol new file mode 100644 index 00000000..3ea49741 --- /dev/null +++ b/contracts/avalanche/connectors/benqi/main.sol @@ -0,0 +1,441 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title Benqi. + * @dev Lending & Borrowing. + */ + +import { TokenInterface } from "../../common/interfaces.sol"; +import { Stores } from "../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; +import { QiAVAXInterface, QiTokenInterface } from "./interface.sol"; + +abstract contract BenqiResolver is Events, Helpers { + /** + * @dev Deposit AVAX/ARC20_Token. + * @notice Deposit a token to Benqi for lending / collaterization. + * @param token The address of the token to deposit. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositRaw( + address token, + address qiToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + enterMarket(qiToken); + if (token == avaxAddr) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + QiAVAXInterface(qiToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + approve(tokenContract, qiToken, _amt); + require(QiTokenInterface(qiToken).mint(_amt) == 0, "deposit-failed"); + } + setUint(setId, _amt); + + _eventName = "LogDeposit(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, _amt, getId, setId); + } + + /** + * @dev Deposit AVAX/ARC20_Token using the Mapping. + * @notice Deposit a token to Benqi for lending / collaterization. + * @param tokenId The token id of the token to deposit.(For eg: AVAX-A) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = depositRaw(token, qiToken, amt, getId, setId); + } + + /** + * @dev Withdraw AVAX/ARC20_Token. + * @notice Withdraw deposited token from Benqi + * @param token The address of the token to withdraw. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawRaw( + address token, + address qiToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + QiTokenInterface qiTokenContract = QiTokenInterface(qiToken); + if (_amt == uint(-1)) { + TokenInterface tokenContract = TokenInterface(token); + uint initialBal = token == avaxAddr ? address(this).balance : tokenContract.balanceOf(address(this)); + require(qiTokenContract.redeem(qiTokenContract.balanceOf(address(this))) == 0, "full-withdraw-failed"); + uint finalBal = token == avaxAddr ? address(this).balance : tokenContract.balanceOf(address(this)); + _amt = finalBal - initialBal; + } else { + require(qiTokenContract.redeemUnderlying(_amt) == 0, "withdraw-failed"); + } + setUint(setId, _amt); + + _eventName = "LogWithdraw(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, _amt, getId, setId); + } + + /** + * @dev Withdraw AVAX/ARC20_Token using the Mapping. + * @notice Withdraw deposited token from Benqi + * @param tokenId The token id of the token to withdraw.(For eg: AVAX-A) + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdraw( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = withdrawRaw(token, qiToken, amt, getId, setId); + } + + /** + * @dev Borrow AVAX/ARC20_Token. + * @notice Borrow a token using Benqi + * @param token The address of the token to borrow. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param amt The amount of the token to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowRaw( + address token, + address qiToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + enterMarket(qiToken); + require(QiTokenInterface(qiToken).borrow(_amt) == 0, "borrow-failed"); + setUint(setId, _amt); + + _eventName = "LogBorrow(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, _amt, getId, setId); + } + + /** + * @dev Borrow AVAX/ARC20_Token using the Mapping. + * @notice Borrow a token using Benqi + * @param tokenId The token id of the token to borrow.(For eg: DAI-A) + * @param amt The amount of the token to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrow( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = borrowRaw(token, qiToken, amt, getId, setId); + } + + /** + * @dev Payback borrowed AVAX/ARC20_Token. + * @notice Payback debt owed. + * @param token The address of the token to payback. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackRaw( + address token, + address qiToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + QiTokenInterface qiTokenContract = QiTokenInterface(qiToken); + _amt = _amt == uint(-1) ? qiTokenContract.borrowBalanceCurrent(address(this)) : _amt; + + if (token == avaxAddr) { + require(address(this).balance >= _amt, "not-enough-avax"); + QiAVAXInterface(qiToken).repayBorrow{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); + approve(tokenContract, qiToken, _amt); + require(qiTokenContract.repayBorrow(_amt) == 0, "repay-failed."); + } + setUint(setId, _amt); + + _eventName = "LogPayback(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, _amt, getId, setId); + } + + /** + * @dev Payback borrowed AVAX/ARC20_Token using the Mapping. + * @notice Payback debt owed. + * @param tokenId The token id of the token to payback.(For eg: BENQI-A) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function payback( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = paybackRaw(token, qiToken, amt, getId, setId); + } + + /** + * @dev Deposit AVAX/ARC20_Token. + * @notice Same as depositRaw. The only difference is this method stores qiToken amount in set ID. + * @param token The address of the token to deposit. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of qiTokens received. + */ + function depositQiTokenRaw( + address token, + address qiToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + enterMarket(qiToken); + + QiTokenInterface qitokenContract = QiTokenInterface(qiToken); + uint initialBal = qitokenContract.balanceOf(address(this)); + + if (token == avaxAddr) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + QiAVAXInterface(qiToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + approve(tokenContract, qiToken, _amt); + require(qitokenContract.mint(_amt) == 0, "deposit-qitoken-failed."); + } + + uint _cAmt; + + { + uint finalBal = qitokenContract.balanceOf(address(this)); + _cAmt = sub(finalBal, initialBal); + + setUint(setId, _cAmt); + } + + _eventName = "LogDepositQiToken(address,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, _amt, _cAmt, getId, setId); + } + + /** + * @dev Deposit AVAX/ARC20_Token using the Mapping. + * @notice Same as deposit. The only difference is this method stores qiToken amount in set ID. + * @param tokenId The token id of the token to depositQiToken.(For eg: DAI-A) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of qiTokens received. + */ + function depositQiToken( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = depositQiTokenRaw(token, qiToken, amt, getId, setId); + } + + /** + * @dev Withdraw QiAVAX/QiARC20_Token using qiToken Amt. + * @notice Same as withdrawRaw. The only difference is this method fetch qiToken amount in get ID. + * @param token The address of the token to withdraw. (For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiToken The address of the corresponding qiToken. + * @param qiTokenAmt The amount of qiTokens to withdraw + * @param getId ID to retrieve qiTokenAmt + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawQiTokenRaw( + address token, + address qiToken, + uint qiTokenAmt, + uint getId, + uint setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _cAmt = getUint(getId, qiTokenAmt); + require(token != address(0) && qiToken != address(0), "invalid token/qitoken address"); + + QiTokenInterface qiTokenContract = QiTokenInterface(qiToken); + TokenInterface tokenContract = TokenInterface(token); + _cAmt = _cAmt == uint(-1) ? qiTokenContract.balanceOf(address(this)) : _cAmt; + + uint withdrawAmt; + { + uint initialBal = token != avaxAddr ? tokenContract.balanceOf(address(this)) : address(this).balance; + require(qiTokenContract.redeem(_cAmt) == 0, "redeem-failed"); + uint finalBal = token != avaxAddr ? tokenContract.balanceOf(address(this)) : address(this).balance; + + withdrawAmt = sub(finalBal, initialBal); + } + + setUint(setId, withdrawAmt); + + _eventName = "LogWithdrawQiToken(address,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, qiToken, withdrawAmt, _cAmt, getId, setId); + } + + /** + * @dev Withdraw QiAVAX/QiARC20_Token using qiToken Amt & the Mapping. + * @notice Same as withdraw. The only difference is this method fetch qiToken amount in get ID. + * @param tokenId The token id of the token to withdraw QiToken.(For eg: AVAX-A) + * @param qiTokenAmt The amount of qiTokens to withdraw + * @param getId ID to retrieve qiTokenAmt + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawQiToken( + string calldata tokenId, + uint qiTokenAmt, + uint getId, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address qiToken) = qiMapping.getMapping(tokenId); + (_eventName, _eventParam) = withdrawQiTokenRaw(token, qiToken, qiTokenAmt, getId, setId); + } + + /** + * @dev Liquidate a position. + * @notice Liquidate a position. + * @param borrower Borrower's Address. + * @param tokenToPay The address of the token to pay for liquidation.(For AVAX: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param qiTokenPay Corresponding qiToken address. + * @param tokenInReturn The address of the token to return for liquidation. + * @param qiTokenColl Corresponding qiToken address. + * @param amt The token amount to pay for liquidation. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of paid for liquidation. + */ + function liquidateRaw( + address borrower, + address tokenToPay, + address qiTokenPay, + address tokenInReturn, + address qiTokenColl, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + require(tokenToPay != address(0) && qiTokenPay != address(0), "invalid token/qitoken address"); + require(tokenInReturn != address(0) && qiTokenColl != address(0), "invalid token/qitoken address"); + + QiTokenInterface qiTokenContract = QiTokenInterface(qiTokenPay); + + { + (,, uint shortfal) = troller.getAccountLiquidity(borrower); + require(shortfal != 0, "account-cannot-be-liquidated"); + _amt = _amt == uint(-1) ? qiTokenContract.borrowBalanceCurrent(borrower) : _amt; + } + + if (tokenToPay == avaxAddr) { + require(address(this).balance >= _amt, "not-enough-avax"); + QiAVAXInterface(qiTokenPay).liquidateBorrow{value: _amt}(borrower, qiTokenColl); + } else { + TokenInterface tokenContract = TokenInterface(tokenToPay); + require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); + approve(tokenContract, qiTokenPay, _amt); + require(qiTokenContract.liquidateBorrow(borrower, _amt, qiTokenColl) == 0, "liquidate-failed"); + } + + setUint(setId, _amt); + + _eventName = "LogLiquidate(address,address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + address(this), + tokenToPay, + tokenInReturn, + _amt, + getId, + setId + ); + } + + /** + * @dev Liquidate a position using the mapping. + * @notice Liquidate a position using the mapping. + * @param borrower Borrower's Address. + * @param tokenIdToPay token id of the token to pay for liquidation.(For eg: AVAX-A) + * @param tokenIdInReturn token id of the token to return for liquidation.(For eg: USDC-A) + * @param amt token amount to pay for liquidation. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of paid for liquidation. + */ + function liquidate( + address borrower, + string calldata tokenIdToPay, + string calldata tokenIdInReturn, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address tokenToPay, address qiTokenToPay) = qiMapping.getMapping(tokenIdToPay); + (address tokenInReturn, address qiTokenColl) = qiMapping.getMapping(tokenIdInReturn); + + (_eventName, _eventParam) = liquidateRaw( + borrower, + tokenToPay, + qiTokenToPay, + tokenInReturn, + qiTokenColl, + amt, + getId, + setId + ); + } +} + +contract ConnectV2Benqi is BenqiResolver { + string public name = "Benqi-v1.1"; +} diff --git a/contracts/avalanche/mapping/benqi.sol b/contracts/avalanche/mapping/benqi.sol new file mode 100644 index 00000000..430ce7fe --- /dev/null +++ b/contracts/avalanche/mapping/benqi.sol @@ -0,0 +1,137 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface IndexInterface { + function master() external view returns (address); +} + +interface ConnectorsInterface { + function chief(address) external view returns (bool); +} + +interface QiTokenInterface { + function isQiToken() external view returns (bool); + function underlying() external view returns (address); +} + +abstract contract Helpers { + + struct TokenMap { + address qitoken; + address token; + } + + event LogQiTokenAdded(string indexed name, address indexed token, address indexed qitoken); + event LogQiTokenUpdated(string indexed name, address indexed token, address indexed qitoken); + + ConnectorsInterface public immutable connectors; + + // InstaIndex Address. + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + + address public constant avaxAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + mapping (string => TokenMap) public qiTokenMapping; + + modifier isChief { + require(msg.sender == instaIndex.master() || connectors.chief(msg.sender), "not-an-chief"); + _; + } + + constructor(address _connectors) { + connectors = ConnectorsInterface(_connectors); + } + + function _addQitokenMapping( + string[] memory _names, + address[] memory _tokens, + address[] memory _qitokens + ) internal { + require(_names.length == _tokens.length, "addQitokenMapping: not same length"); + require(_names.length == _qitokens.length, "addQitokenMapping: not same length"); + + for (uint i = 0; i < _qitokens.length; i++) { + TokenMap memory _data = qiTokenMapping[_names[i]]; + + require(_data.qitoken == address(0), "addQitokenMapping: mapping added already"); + require(_data.token == address(0), "addQitokenMapping: mapping added already"); + + require(_tokens[i] != address(0), "addQitokenMapping: _tokens address not vaild"); + require(_qitokens[i] != address(0), "addQitokenMapping: _qitokens address not vaild"); + + QiTokenInterface _qitokenContract = QiTokenInterface(_qitokens[i]); + + require(_qitokenContract.isQiToken(), "addQitokenMapping: not a qiToken"); + if (_tokens[i] != avaxAddr) { + require(_qitokenContract.underlying() == _tokens[i], "addQitokenMapping: mapping mismatch"); + } + + qiTokenMapping[_names[i]] = TokenMap( + _qitokens[i], + _tokens[i] + ); + emit LogQiTokenAdded(_names[i], _tokens[i], _qitokens[i]); + } + } + + function updateQitokenMapping( + string[] calldata _names, + address[] memory _tokens, + address[] calldata _qitokens + ) external { + require(msg.sender == instaIndex.master(), "not-master"); + + require(_names.length == _tokens.length, "updateQitokenMapping: not same length"); + require(_names.length == _qitokens.length, "updateQitokenMapping: not same length"); + + for (uint i = 0; i < _qitokens.length; i++) { + TokenMap memory _data = qiTokenMapping[_names[i]]; + + require(_data.qitoken != address(0), "updateQitokenMapping: mapping does not exist"); + require(_data.token != address(0), "updateQitokenMapping: mapping does not exist"); + + require(_tokens[i] != address(0), "updateQitokenMapping: _tokens address not vaild"); + require(_qitokens[i] != address(0), "updateQitokenMapping: _qitokens address not vaild"); + + QiTokenInterface _qitokenContract = QiTokenInterface(_qitokens[i]); + + require(_qitokenContract.isQiToken(), "updateQitokenMapping: not a qiToken"); + if (_tokens[i] != avaxAddr) { + require(_qitokenContract.underlying() == _tokens[i], "addQitokenMapping: mapping mismatch"); + } + + qiTokenMapping[_names[i]] = TokenMap( + _qitokens[i], + _tokens[i] + ); + emit LogQiTokenUpdated(_names[i], _tokens[i], _qitokens[i]); + } + } + + function addQitokenMapping( + string[] memory _names, + address[] memory _tokens, + address[] memory _qitokens + ) external isChief { + _addQitokenMapping(_names, _tokens, _qitokens); + } + + function getMapping(string memory _tokenId) external view returns (address, address) { + TokenMap memory _data = qiTokenMapping[_tokenId]; + return (_data.token, _data.qitoken); + } + +} + +contract InstaBenqiMapping is Helpers { + string constant public name = "Benqi-Mapping-v1.0"; + + constructor( + address _connectors, + string[] memory _qitokenNames, + address[] memory _tokens, + address[] memory _qitokens + ) Helpers(_connectors) { + _addQitokenMapping(_qitokenNames, _tokens, _qitokens); + } +} \ No newline at end of file diff --git a/contracts/avalanche/static/basic.sol b/contracts/avalanche/static/basic.sol new file mode 100644 index 00000000..15294619 --- /dev/null +++ b/contracts/avalanche/static/basic.sol @@ -0,0 +1,77 @@ +pragma solidity ^0.7.0; + +/** + * @title StaticConnectBasic. + * @dev Static Connector to withdraw assets. + */ + +interface TokenInterface { + function balanceOf(address) external view returns (uint); + function transfer(address, uint) external returns (bool); +} + +interface AccountInterface { + function isAuth(address) external view returns (bool); +} + +interface EventInterface { + function emitEvent(uint _connectorType, uint _connectorID, bytes32 _eventCode, bytes calldata _eventData) external; +} + +contract Memory { + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; + } + + function connectorID() public pure returns(uint _type, uint _id) { + (_type, _id) = (2, 1); + } + +} + +contract BasicResolver is Memory { + + event LogWithdraw(address arc20, uint tokenAmt, address to); + + /** + * @dev AVAX Address. + */ + address constant internal avaxAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + /** + * @dev Withdraw Assets To Smart Account. + * @param arc20 Token Address. + * @param tokenAmt Token Amount. + */ + function withdraw( + address arc20, + uint tokenAmt + ) external payable { + uint amt; + if (arc20 == avaxAddr) { + amt = tokenAmt == uint(-1) ? address(this).balance : tokenAmt; + msg.sender.transfer(amt); + } else { + TokenInterface token = TokenInterface(arc20); + amt = tokenAmt == uint(-1) ? token.balanceOf(address(this)) : tokenAmt; + token.transfer(msg.sender, amt); + } + + emit LogWithdraw(arc20, amt, msg.sender); + + bytes32 _eventCode = keccak256("LogWithdraw(address,uint256,address)"); + bytes memory _eventParam = abi.encode(arc20, amt, msg.sender); + (uint _type, uint _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + +} + + +contract StaticConnectBasic is BasicResolver { + string public constant name = "Static-Basic-v1"; +} \ No newline at end of file From 5ff2546efef4d70a014741edd3fdd58f61f35434 Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Thu, 30 Sep 2021 11:17:17 +0400 Subject: [PATCH 2/6] Update addresses, Fixed Qi reward claim --- contracts/avalanche/common/stores.sol | 2 +- contracts/avalanche/connectors/Qi/helpers.sol | 10 +++++++-- .../avalanche/connectors/Qi/interface.sol | 6 ++--- contracts/avalanche/connectors/Qi/main.sol | 22 +++++++++---------- .../avalanche/connectors/benqi/interface.sol | 2 +- contracts/avalanche/connectors/benqi/main.sol | 2 +- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/contracts/avalanche/common/stores.sol b/contracts/avalanche/common/stores.sol index 783a94a3..d79c8041 100644 --- a/contracts/avalanche/common/stores.sol +++ b/contracts/avalanche/common/stores.sol @@ -13,7 +13,7 @@ abstract contract Stores { /** * @dev Return Wrapped AVAX address */ - address constant internal wavaxAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address constant internal wavaxAddr = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; /** * @dev Return memory variable address diff --git a/contracts/avalanche/connectors/Qi/helpers.sol b/contracts/avalanche/connectors/Qi/helpers.sol index b0a57a94..7ef95952 100644 --- a/contracts/avalanche/connectors/Qi/helpers.sol +++ b/contracts/avalanche/connectors/Qi/helpers.sol @@ -9,18 +9,24 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Benqi Comptroller */ - ComptrollerInterface internal constant troller = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); + ComptrollerInterface internal constant troller = ComptrollerInterface(0x486Af39519B4Dc9a7fCcd318217352830E8AD9b4); /** * @dev Reward Token */ - QiInterface internal constant benqiToken = QiInterface(0xc00e94Cb662C3520282E6f5717214004A7f26888); + QiInterface internal constant benqiToken = QiInterface(0x8729438EB15e2C8B576fCc6AeCdA6A148776C0F5); /** * @dev Benqi Mapping */ BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); + /** + * @dev Benqi reward token type to show BENQI or AVAX + */ + uint8 internal constant rewardQi = 0; + uint8 internal constant rewardAvax = 1; + function getMergedQiTokens( string[] calldata supplyIds, string[] calldata borrowIds diff --git a/contracts/avalanche/connectors/Qi/interface.sol b/contracts/avalanche/connectors/Qi/interface.sol index 0df5011e..351fd404 100644 --- a/contracts/avalanche/connectors/Qi/interface.sol +++ b/contracts/avalanche/connectors/Qi/interface.sol @@ -1,9 +1,9 @@ pragma solidity ^0.7.0; interface ComptrollerInterface { - function claimReward(address holder) external; - function claimReward(address holder, address[] calldata) external; - function claimReward(address[] calldata holders, address[] calldata qiTokens, bool borrowers, bool suppliers) external; + function claimReward(uint8 rewardType, address holder) external; + function claimReward(uint8 rewardType, address holder, address[] calldata) external; + function claimReward(uint8 rewardType, address[] calldata holders, address[] calldata qiTokens, bool borrowers, bool suppliers) external; } interface QiInterface { diff --git a/contracts/avalanche/connectors/Qi/main.sol b/contracts/avalanche/connectors/Qi/main.sol index ebc0cf96..97a1cf5b 100644 --- a/contracts/avalanche/connectors/Qi/main.sol +++ b/contracts/avalanche/connectors/Qi/main.sol @@ -13,14 +13,14 @@ import { Events } from "./events.sol"; abstract contract BenqiResolver is Events, Helpers { /** - * @dev Claim Accrued Reward Token. - * @notice Claim Accrued Reward Token. + * @dev Claim Accrued Qi Token. + * @notice Claim Accrued Qi Token. * @param setId ID stores the amount of Reward claimed. */ function ClaimReward(uint256 setId) external payable returns (string memory _eventName, bytes memory _eventParam) { TokenInterface _benqiToken = TokenInterface(address(benqiToken)); uint intialBal = _benqiToken.balanceOf(address(this)); - troller.claimReward(address(this)); + troller.claimReward(rewardQi, address(this)); uint finalBal = _benqiToken.balanceOf(address(this)); uint amt = sub(finalBal, intialBal); @@ -31,8 +31,8 @@ abstract contract BenqiResolver is Events, Helpers { } /** - * @dev Claim Accrued Reward Token. - * @notice Claim Accrued Reward Token. + * @dev Claim Accrued Qi Token. + * @notice Claim Accrued Qi Token. * @param tokenIds Array of supplied and borrowed token IDs. * @param setId ID stores the amount of Reward claimed. */ @@ -48,7 +48,7 @@ abstract contract BenqiResolver is Events, Helpers { TokenInterface _benqiToken = TokenInterface(address(benqiToken)); uint intialBal = _benqiToken.balanceOf(address(this)); - troller.claimReward(address(this), qitokens); + troller.claimReward(rewardQi, address(this), qitokens); uint finalBal = _benqiToken.balanceOf(address(this)); uint amt = sub(finalBal, intialBal); @@ -59,8 +59,8 @@ abstract contract BenqiResolver is Events, Helpers { } /** - * @dev Claim Accrued Reward Token. - * @notice Claim Accrued Reward Token. + * @dev Claim Accrued Qi Token. + * @notice Claim Accrued Qi Token. * @param supplyTokenIds Array of supplied tokenIds. * @param borrowTokenIds Array of borrowed tokenIds. * @param setId ID stores the amount of Reward claimed. @@ -73,7 +73,7 @@ abstract contract BenqiResolver is Events, Helpers { TokenInterface _benqiToken = TokenInterface(address(benqiToken)); uint intialBal = _benqiToken.balanceOf(address(this)); - troller.claimReward(holders, qitokens, isBorrow, isSupply); + troller.claimReward(rewardQi, holders, qitokens, isBorrow, isSupply); uint finalBal = _benqiToken.balanceOf(address(this)); uint amt = sub(finalBal, intialBal); @@ -98,6 +98,6 @@ abstract contract BenqiResolver is Events, Helpers { } } -contract ConnectBenqi is BenqiResolver { - string public constant name = "Benqi-v1.0"; +contract ConnectV2Benqi is BenqiResolver { + string public constant name = "Benqi-v1"; } diff --git a/contracts/avalanche/connectors/benqi/interface.sol b/contracts/avalanche/connectors/benqi/interface.sol index 26709a05..c88bad9e 100644 --- a/contracts/avalanche/connectors/benqi/interface.sol +++ b/contracts/avalanche/connectors/benqi/interface.sol @@ -27,7 +27,7 @@ interface ComptrollerInterface { function exitMarket(address qiTokenAddress) external returns (uint); function getAssetsIn(address account) external view returns (address[] memory); function getAccountLiquidity(address account) external view returns (uint, uint, uint); - function claimReward(address) external; + function claimReward(uint8 rewardType, address) external; } interface BenqiMappingInterface { diff --git a/contracts/avalanche/connectors/benqi/main.sol b/contracts/avalanche/connectors/benqi/main.sol index 3ea49741..1a56540c 100644 --- a/contracts/avalanche/connectors/benqi/main.sol +++ b/contracts/avalanche/connectors/benqi/main.sol @@ -437,5 +437,5 @@ abstract contract BenqiResolver is Events, Helpers { } contract ConnectV2Benqi is BenqiResolver { - string public name = "Benqi-v1.1"; + string public name = "Benqi-v1"; } From 9fa4499b6903ad60b40fbb7e80256ac39407a8b3 Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Fri, 8 Oct 2021 11:21:31 +0400 Subject: [PATCH 3/6] Fix feedback from instadapp, update interfaces, addresses --- contracts/avalanche/common/interfaces.sol | 5 -- contracts/avalanche/common/stores.sol | 9 +-- contracts/avalanche/connectors/benqi/main.sol | 2 +- contracts/avalanche/mapping/benqi.sol | 33 +++++--- contracts/avalanche/static/basic.sol | 77 ------------------- 5 files changed, 25 insertions(+), 101 deletions(-) delete mode 100644 contracts/avalanche/static/basic.sol diff --git a/contracts/avalanche/common/interfaces.sol b/contracts/avalanche/common/interfaces.sol index f9d704af..ea9c362d 100644 --- a/contracts/avalanche/common/interfaces.sol +++ b/contracts/avalanche/common/interfaces.sol @@ -15,11 +15,6 @@ interface MemoryInterface { function setUint(uint id, uint val) external; } -interface InstaMapping { - function qiTokenMapping(address) external view returns (address); - function gemJoinMapping(bytes32) external view returns (address); -} - interface AccountInterface { function enable(address) external; function disable(address) external; diff --git a/contracts/avalanche/common/stores.sol b/contracts/avalanche/common/stores.sol index d79c8041..aed57250 100644 --- a/contracts/avalanche/common/stores.sol +++ b/contracts/avalanche/common/stores.sol @@ -1,6 +1,6 @@ pragma solidity ^0.7.0; -import { MemoryInterface, InstaMapping } from "./interfaces.sol"; +import { MemoryInterface } from "./interfaces.sol"; abstract contract Stores { @@ -18,12 +18,7 @@ abstract contract Stores { /** * @dev Return memory variable address */ - MemoryInterface constant internal instaMemory = MemoryInterface(0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F); - - /** - * @dev Return InstaDApp Mapping Addresses - */ - InstaMapping constant internal instaMapping = InstaMapping(0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88); + MemoryInterface constant internal instaMemory = MemoryInterface(0x3254Ce8f5b1c82431B8f21Df01918342215825C2); /** * @dev Get Uint value from InstaMemory Contract. diff --git a/contracts/avalanche/connectors/benqi/main.sol b/contracts/avalanche/connectors/benqi/main.sol index 1a56540c..97d8daa3 100644 --- a/contracts/avalanche/connectors/benqi/main.sol +++ b/contracts/avalanche/connectors/benqi/main.sol @@ -436,6 +436,6 @@ abstract contract BenqiResolver is Events, Helpers { } } -contract ConnectV2Benqi is BenqiResolver { +contract ConnectV2BenqiAvalanche is BenqiResolver { string public name = "Benqi-v1"; } diff --git a/contracts/avalanche/mapping/benqi.sol b/contracts/avalanche/mapping/benqi.sol index 430ce7fe..0ce2579c 100644 --- a/contracts/avalanche/mapping/benqi.sol +++ b/contracts/avalanche/mapping/benqi.sol @@ -14,6 +14,10 @@ interface QiTokenInterface { function underlying() external view returns (address); } +interface MappingControllerInterface { + function hasRole(address,address) external view returns (bool); +} + abstract contract Helpers { struct TokenMap { @@ -24,10 +28,13 @@ abstract contract Helpers { event LogQiTokenAdded(string indexed name, address indexed token, address indexed qitoken); event LogQiTokenUpdated(string indexed name, address indexed token, address indexed qitoken); - ConnectorsInterface public immutable connectors; - + // InstaConnectorsV2 + ConnectorsInterface public constant connectors = ConnectorsInterface(0x127d8cD0E2b2E0366D522DeA53A787bfE9002C14); // InstaIndex Address. - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + IndexInterface public constant instaIndex = IndexInterface(0x6CE3e607C808b4f4C26B7F6aDAeB619e49CAbb25); + + // InstaMappingController Address. + MappingControllerInterface public constant mappingController = MappingControllerInterface(0xF2113d0c99f36D7D6F6c6FAf05E0863892255999); address public constant avaxAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; @@ -38,8 +45,14 @@ abstract contract Helpers { _; } - constructor(address _connectors) { - connectors = ConnectorsInterface(_connectors); + modifier hasRoleOrIsChief { + require( + msg.sender == instaIndex.master() || + connectors.chief(msg.sender) || + mappingController.hasRole(address(this), msg.sender), + "not-an-chief/controller" + ); + _; } function _addQitokenMapping( @@ -78,8 +91,7 @@ abstract contract Helpers { string[] calldata _names, address[] memory _tokens, address[] calldata _qitokens - ) external { - require(msg.sender == instaIndex.master(), "not-master"); + ) external isChief { require(_names.length == _tokens.length, "updateQitokenMapping: not same length"); require(_names.length == _qitokens.length, "updateQitokenMapping: not same length"); @@ -112,7 +124,7 @@ abstract contract Helpers { string[] memory _names, address[] memory _tokens, address[] memory _qitokens - ) external isChief { + ) external hasRoleOrIsChief { _addQitokenMapping(_names, _tokens, _qitokens); } @@ -123,15 +135,14 @@ abstract contract Helpers { } -contract InstaBenqiMapping is Helpers { +contract InstaBenqiMappingAvalanche is Helpers { string constant public name = "Benqi-Mapping-v1.0"; constructor( - address _connectors, string[] memory _qitokenNames, address[] memory _tokens, address[] memory _qitokens - ) Helpers(_connectors) { + ) { _addQitokenMapping(_qitokenNames, _tokens, _qitokens); } } \ No newline at end of file diff --git a/contracts/avalanche/static/basic.sol b/contracts/avalanche/static/basic.sol deleted file mode 100644 index 15294619..00000000 --- a/contracts/avalanche/static/basic.sol +++ /dev/null @@ -1,77 +0,0 @@ -pragma solidity ^0.7.0; - -/** - * @title StaticConnectBasic. - * @dev Static Connector to withdraw assets. - */ - -interface TokenInterface { - function balanceOf(address) external view returns (uint); - function transfer(address, uint) external returns (bool); -} - -interface AccountInterface { - function isAuth(address) external view returns (bool); -} - -interface EventInterface { - function emitEvent(uint _connectorType, uint _connectorID, bytes32 _eventCode, bytes calldata _eventData) external; -} - -contract Memory { - - /** - * @dev Return InstaEvent Address. - */ - function getEventAddr() internal pure returns (address) { - return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; - } - - function connectorID() public pure returns(uint _type, uint _id) { - (_type, _id) = (2, 1); - } - -} - -contract BasicResolver is Memory { - - event LogWithdraw(address arc20, uint tokenAmt, address to); - - /** - * @dev AVAX Address. - */ - address constant internal avaxAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - - /** - * @dev Withdraw Assets To Smart Account. - * @param arc20 Token Address. - * @param tokenAmt Token Amount. - */ - function withdraw( - address arc20, - uint tokenAmt - ) external payable { - uint amt; - if (arc20 == avaxAddr) { - amt = tokenAmt == uint(-1) ? address(this).balance : tokenAmt; - msg.sender.transfer(amt); - } else { - TokenInterface token = TokenInterface(arc20); - amt = tokenAmt == uint(-1) ? token.balanceOf(address(this)) : tokenAmt; - token.transfer(msg.sender, amt); - } - - emit LogWithdraw(arc20, amt, msg.sender); - - bytes32 _eventCode = keccak256("LogWithdraw(address,uint256,address)"); - bytes memory _eventParam = abi.encode(arc20, amt, msg.sender); - (uint _type, uint _id) = connectorID(); - EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); - } - -} - - -contract StaticConnectBasic is BasicResolver { - string public constant name = "Static-Basic-v1"; -} \ No newline at end of file From eadcd73ed1e34414a5202accfe8518aef937e235 Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Thu, 21 Oct 2021 12:54:16 +0400 Subject: [PATCH 4/6] Updated contract name --- contracts/avalanche/connectors/Qi/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/avalanche/connectors/Qi/main.sol b/contracts/avalanche/connectors/Qi/main.sol index 97a1cf5b..11d21488 100644 --- a/contracts/avalanche/connectors/Qi/main.sol +++ b/contracts/avalanche/connectors/Qi/main.sol @@ -98,6 +98,6 @@ abstract contract BenqiResolver is Events, Helpers { } } -contract ConnectV2Benqi is BenqiResolver { +contract ConnectV2QiAvalanche is BenqiResolver { string public constant name = "Benqi-v1"; } From a47eade8f728cb0d0fb9e198e340961fb251c5d2 Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Wed, 27 Oct 2021 16:24:20 +0400 Subject: [PATCH 5/6] Update BenqiMappingInterface contract address --- contracts/avalanche/connectors/Qi/helpers.sol | 2 +- contracts/avalanche/connectors/benqi/helpers.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/avalanche/connectors/Qi/helpers.sol b/contracts/avalanche/connectors/Qi/helpers.sol index 7ef95952..0a0d5864 100644 --- a/contracts/avalanche/connectors/Qi/helpers.sol +++ b/contracts/avalanche/connectors/Qi/helpers.sol @@ -19,7 +19,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Benqi Mapping */ - BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xFb0388DAF4004D34D5A3209E1E5dd8C96a2A6D9a); /** * @dev Benqi reward token type to show BENQI or AVAX diff --git a/contracts/avalanche/connectors/benqi/helpers.sol b/contracts/avalanche/connectors/benqi/helpers.sol index bc5b260f..a12d090c 100644 --- a/contracts/avalanche/connectors/benqi/helpers.sol +++ b/contracts/avalanche/connectors/benqi/helpers.sol @@ -13,7 +13,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Benqi Mapping */ - BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xFb0388DAF4004D34D5A3209E1E5dd8C96a2A6D9a); /** * @dev enter benqi market From 016903b081e865c6db5534caeab0dab14342fb6a Mon Sep 17 00:00:00 2001 From: babkendev01 Date: Wed, 27 Oct 2021 20:50:22 +0400 Subject: [PATCH 6/6] Updated mapping contract address with correct wrapped token name --- contracts/avalanche/connectors/Qi/helpers.sol | 2 +- contracts/avalanche/connectors/benqi/helpers.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/avalanche/connectors/Qi/helpers.sol b/contracts/avalanche/connectors/Qi/helpers.sol index 0a0d5864..74c308fd 100644 --- a/contracts/avalanche/connectors/Qi/helpers.sol +++ b/contracts/avalanche/connectors/Qi/helpers.sol @@ -19,7 +19,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Benqi Mapping */ - BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xFb0388DAF4004D34D5A3209E1E5dd8C96a2A6D9a); + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe19Fba29ac9BAACc1F584aEcD9C98B4F6fC58ba6); /** * @dev Benqi reward token type to show BENQI or AVAX diff --git a/contracts/avalanche/connectors/benqi/helpers.sol b/contracts/avalanche/connectors/benqi/helpers.sol index a12d090c..ef0e891d 100644 --- a/contracts/avalanche/connectors/benqi/helpers.sol +++ b/contracts/avalanche/connectors/benqi/helpers.sol @@ -13,7 +13,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Benqi Mapping */ - BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xFb0388DAF4004D34D5A3209E1E5dd8C96a2A6D9a); + BenqiMappingInterface internal constant qiMapping = BenqiMappingInterface(0xe19Fba29ac9BAACc1F584aEcD9C98B4F6fC58ba6); /** * @dev enter benqi market