diff --git a/.circleci/config.yml b/.circleci/config.yml index 4f784e1..71af300 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ jobs: # a collection of steps - image: circleci/node:12.16.2 # ...with this image as the primary container; this is where all `steps` will run steps: # a collection of executable commands - checkout # special step to check out source code to working directory - - restore_cache: # special step to restore the dependency cache + - restore_cache: # restore the dependency cache # Read about caching dependencies: https://circleci.com/docs/2.0/caching/ name: Restore Yarn Package Cache key: yarn-packages-{{ checksum "yarn.lock" }} @@ -18,30 +18,37 @@ jobs: # a collection of steps key: yarn-packages-{{ checksum "yarn.lock" }} paths: - ./node_modules + - restore_cache: # restore hardhat compile cache + name: Restore Hardhat Compilation Cache + key: solidity-files-cache- - run: # Compile name: Compile command: yarn compile + - save_cache: # special step to save the hardhat compile cache + name: Save Hardhat Compilation Cache + key: solidity-files-cache-{{ checksum "./cache/solidity-files-cache.json" }} + paths: + - ./cache/solidity-files-cache.json - run: # Formatting name: Prettier Check command: yarn prettier --check . - run: # Linting name: ESLint command: yarn lint - - restore_cache: # special step to restore the Hardhat Network Fork Cache - # Read about caching dependencies: https://circleci.com/docs/2.0/caching/ + - restore_cache: # restore the Hardhat Network Fork Cache name: Restore Hardhat Network Fork Cache - key: hardhat-network-fork + key: v1-hardhat-network-fork-cache - run: # Tests name: Tests using hardhat mainnet fork and gas reporter command: REPORT_GAS=1 yarn test + - save_cache: # special step to save the Hardhat Network Fork cache + name: Save Hardhat Network Fork Cache + key: v1-hardhat-network-fork-cache + paths: + - ./cache/hardhat-network-fork - run: # Codechecks name: Codechecks gas reporting command: npx codechecks - - save_cache: # special step to save the Hardhat Network Fork cache - name: Save Hardhat Network Fork Cache - key: hardhat-network-fork - paths: - - ./cache/hardhat-network-fork # - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/ # path: coverage # prefix: coverage diff --git a/.solhintignore b/.solhintignore index fa6f76e..240f776 100644 --- a/.solhintignore +++ b/.solhintignore @@ -1,4 +1,5 @@ node_modules/ contracts/constants +contracts/dependencies contracts/functions contracts/vendor \ No newline at end of file diff --git a/contracts/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol b/contracts/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol index 09b837d..304b8be 100644 --- a/contracts/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol +++ b/contracts/contracts/gelato/conditions/ConditionCompareUintsFromTwoSources.sol @@ -4,7 +4,7 @@ pragma solidity 0.7.4; import { GelatoConditionsStandard } from "@gelatonetwork/core/contracts/conditions/GelatoConditionsStandard.sol"; -import {SafeMath} from "@gelatonetwork/core/contracts/external/SafeMath.sol"; +import {SafeMath} from "../../../vendor/SafeMath.sol"; import { IGelatoCore } from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; diff --git a/contracts/dependencies/GelatoTestDependencies.sol b/contracts/dependencies/GelatoTestDependencies.sol new file mode 100644 index 0000000..aec4339 --- /dev/null +++ b/contracts/dependencies/GelatoTestDependencies.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.6.10; + +import "@gelatonetwork/core/contracts/gelato_core/GelatoCore.sol"; + +// solhint-disable-next-line no-empty-blocks +contract GelatoTestDependencies { + +} diff --git a/contracts/dependencies/InstaDapp/connectors/compound.sol b/contracts/dependencies/InstaDapp/connectors/compound.sol new file mode 100644 index 0000000..7a3dcab --- /dev/null +++ b/contracts/dependencies/InstaDapp/connectors/compound.sol @@ -0,0 +1,685 @@ +pragma solidity ^0.6.0; + +interface CTokenInterface { + function mint(uint256 mintAmount) external returns (uint256); + + function redeem(uint256 redeemTokens) external returns (uint256); + + function borrow(uint256 borrowAmount) external returns (uint256); + + function repayBorrow(uint256 repayAmount) external returns (uint256); + + function repayBorrowBehalf(address borrower, uint256 repayAmount) + external + returns (uint256); // For ERC20 + + function liquidateBorrow( + address borrower, + uint256 repayAmount, + address cTokenCollateral + ) external returns (uint256); + + function borrowBalanceCurrent(address account) external returns (uint256); + + function redeemUnderlying(uint256 redeemAmount) external returns (uint256); + + function exchangeRateCurrent() external returns (uint256); + + function balanceOf(address owner) external view returns (uint256 balance); +} + +interface CETHInterface { + function mint() external payable; + + function repayBorrow() external payable; + + function repayBorrowBehalf(address borrower) external payable; + + function liquidateBorrow(address borrower, address cTokenCollateral) + external + payable; +} + +interface TokenInterface { + function allowance(address, address) external view returns (uint256); + + function balanceOf(address) external view returns (uint256); + + function approve(address, uint256) external; + + function transfer(address, uint256) external returns (bool); + + function transferFrom( + address, + address, + uint256 + ) external returns (bool); +} + +interface ComptrollerInterface { + function enterMarkets(address[] calldata cTokens) + external + returns (uint256[] memory); + + function exitMarket(address cTokenAddress) external returns (uint256); + + function getAssetsIn(address account) + external + view + returns (address[] memory); + + function getAccountLiquidity(address account) + external + view + returns ( + uint256, + uint256, + uint256 + ); + + function claimComp(address) external; +} + +interface InstaMapping { + function cTokenMapping(address) external view returns (address); +} + +interface MemoryInterface { + function getUint(uint256 _id) external returns (uint256 _num); + + function setUint(uint256 _id, uint256 _val) external; +} + +interface EventInterface { + function emitEvent( + uint256 _connectorType, + uint256 _connectorID, + bytes32 _eventCode, + bytes calldata _eventData + ) external; +} + +contract DSMath { + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + uint256 constant WAD = 10**18; + + function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, WAD), y / 2) / y; + } + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } +} + +contract Helpers is DSMath { + /** + * @dev Return ethereum address + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; // InstaEvent Address + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint256 getId, uint256 val) + internal + returns (uint256 returnVal) + { + returnVal = getId == 0 + ? val + : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint256 setId, uint256 val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Connector Details + */ + function connectorID() public pure returns (uint256 _type, uint256 _id) { + (_type, _id) = (1, 24); + } +} + +contract CompoundHelpers is Helpers { + /** + * @dev Return Compound Comptroller Address + */ + function getComptrollerAddress() internal pure returns (address) { + return 0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B; + } + + /** + * @dev Return COMP Token Address. + */ + function getCompTokenAddress() internal pure returns (address) { + return 0xc00e94Cb662C3520282E6f5717214004A7f26888; + } + + /** + * @dev Return InstaDApp Mapping Addresses + */ + function getMappingAddr() internal pure returns (address) { + return 0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88; // InstaMapping Address + } + + /** + * @dev enter compound market + */ + function enterMarket(address cToken) internal { + ComptrollerInterface troller = ComptrollerInterface( + getComptrollerAddress() + ); + address[] memory markets = troller.getAssetsIn(address(this)); + bool isEntered = false; + for (uint256 i = 0; i < markets.length; i++) { + if (markets[i] == cToken) { + isEntered = true; + } + } + if (!isEntered) { + address[] memory toEnter = new address[](1); + toEnter[0] = cToken; + troller.enterMarkets(toEnter); + } + } +} + +contract BasicResolver is CompoundHelpers { + event LogDeposit( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogWithdraw( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogBorrow( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogPayback( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + /** + * @dev Deposit ETH/ERC20_Token. + * @param token token address to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to deposit. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function deposit( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + enterMarket(cToken); + if (token == getAddressETH()) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + CETHInterface(cToken).mint.value(_amt)(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + tokenContract.approve(cToken, _amt); + require(CTokenInterface(cToken).mint(_amt) == 0, "borrow-failed"); + } + setUint(setId, _amt); + + emit LogDeposit(token, cToken, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogDeposit(address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Withdraw ETH/ERC20_Token. + * @param token token address to withdraw.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to withdraw. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function withdraw( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + CTokenInterface cTokenContract = CTokenInterface(cToken); + if (_amt == uint256(-1)) { + TokenInterface tokenContract = TokenInterface(token); + uint256 initialBal = token == getAddressETH() + ? address(this).balance + : tokenContract.balanceOf(address(this)); + require( + cTokenContract.redeem( + cTokenContract.balanceOf(address(this)) + ) == 0, + "full-withdraw-failed" + ); + uint256 finalBal = token == getAddressETH() + ? address(this).balance + : tokenContract.balanceOf(address(this)); + _amt = finalBal - initialBal; + } else { + require( + cTokenContract.redeemUnderlying(_amt) == 0, + "withdraw-failed" + ); + } + setUint(setId, _amt); + + emit LogWithdraw(token, cToken, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogWithdraw(address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Borrow ETH/ERC20_Token. + * @param token token address to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to borrow. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function borrow( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + enterMarket(cToken); + require(CTokenInterface(cToken).borrow(_amt) == 0, "borrow-failed"); + setUint(setId, _amt); + + emit LogBorrow(token, cToken, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogBorrow(address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Payback borrowed ETH/ERC20_Token. + * @param token token address to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to payback. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function payback( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + CTokenInterface cTokenContract = CTokenInterface(cToken); + _amt = _amt == uint256(-1) + ? cTokenContract.borrowBalanceCurrent(address(this)) + : _amt; + + if (token == getAddressETH()) { + require(address(this).balance >= _amt, "not-enough-eth"); + CETHInterface(cToken).repayBorrow.value(_amt)(); + } else { + TokenInterface tokenContract = TokenInterface(token); + require( + tokenContract.balanceOf(address(this)) >= _amt, + "not-enough-token" + ); + tokenContract.approve(cToken, _amt); + require(cTokenContract.repayBorrow(_amt) == 0, "repay-failed."); + } + setUint(setId, _amt); + + emit LogPayback(token, cToken, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogPayback(address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract ExtraResolver is BasicResolver { + event LogClaimedComp(uint256 compAmt, uint256 setId); + event LogDepositCToken( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 cTokenAmt, + uint256 getId, + uint256 setId + ); + event LogWithdrawCToken( + address indexed token, + address cToken, + uint256 cTokenAmt, + uint256 getId, + uint256 setId + ); + event LogLiquidate( + address indexed borrower, + address indexed tokenToPay, + address indexed tokenInReturn, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + /** + * @dev Claim Accrued COMP Token. + * @param setId Set ctoken amount at this ID in `InstaMemory` Contract. + */ + function ClaimComp(uint256 setId) external payable { + TokenInterface compToken = TokenInterface(getCompTokenAddress()); + uint256 intialBal = compToken.balanceOf(address(this)); + ComptrollerInterface(getComptrollerAddress()).claimComp(address(this)); + uint256 finalBal = compToken.balanceOf(address(this)); + uint256 amt = sub(finalBal, intialBal); + + setUint(setId, amt); + + emit LogClaimedComp(amt, setId); + bytes32 _eventCode = keccak256("LogClaimedComp(uint256,uint256)"); + bytes memory _eventParam = abi.encode(amt, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Deposit ETH/ERC20_Token. + * @param token token address to depositCToken.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to depositCToken. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set ctoken amount at this ID in `InstaMemory` Contract. + */ + function depositCToken( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + enterMarket(cToken); + + CTokenInterface ctokenContract = CTokenInterface(cToken); + uint256 initialBal = ctokenContract.balanceOf(address(this)); + + if (token == getAddressETH()) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + CETHInterface(cToken).mint.value(_amt)(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + tokenContract.approve(cToken, _amt); + require(ctokenContract.mint(_amt) == 0, "deposit-ctoken-failed."); + } + + uint256 finalBal = ctokenContract.balanceOf(address(this)); + uint256 _cAmt = finalBal - initialBal; + setUint(setId, _cAmt); + + emit LogDepositCToken(token, cToken, _amt, _cAmt, getId, setId); + bytes32 _eventCode = keccak256( + "LogDepositCToken(address,address,uint256,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + _cAmt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Withdraw CETH/CERC20_Token using cToken Amt. + * @param token token address to withdraw CToken.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cTokenAmt ctoken amount to withdrawCToken. + * @param getId Get ctoken amount at this ID from `InstaMemory` Contract. + * @param setId Set ctoken amount at this ID in `InstaMemory` Contract. + */ + function withdrawCToken( + address token, + uint256 cTokenAmt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, cTokenAmt); + address cToken = InstaMapping(getMappingAddr()).cTokenMapping(token); + CTokenInterface cTokenContract = CTokenInterface(cToken); + _amt = _amt == uint256(-1) + ? cTokenContract.balanceOf(address(this)) + : _amt; + require(cTokenContract.redeem(_amt) == 0, "redeem-failed"); + setUint(setId, _amt); + + emit LogWithdrawCToken(token, cToken, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogWithdrawCToken(address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + token, + cToken, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Liquidate a position. + * @param borrower Borrower's Address. + * @param tokenToPay token address to pay for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param tokenInReturn token address to return for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt token amount to pay for liquidation. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function liquidate( + address borrower, + address tokenToPay, + address tokenInReturn, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address cTokenPay = InstaMapping(getMappingAddr()).cTokenMapping( + tokenToPay + ); + address cTokenColl = InstaMapping(getMappingAddr()).cTokenMapping( + tokenInReturn + ); + CTokenInterface cTokenContract = CTokenInterface(cTokenPay); + + (, , uint256 shortfal) = ComptrollerInterface(getComptrollerAddress()) + .getAccountLiquidity(borrower); + require(shortfal != 0, "account-cannot-be-liquidated"); + + _amt = _amt == uint256(-1) + ? cTokenContract.borrowBalanceCurrent(borrower) + : _amt; + if (tokenToPay == getAddressETH()) { + require(address(this).balance >= _amt, "not-enought-eth"); + CETHInterface(cTokenPay).liquidateBorrow.value(_amt)( + borrower, + cTokenColl + ); + } else { + TokenInterface tokenContract = TokenInterface(tokenToPay); + require( + tokenContract.balanceOf(address(this)) >= _amt, + "not-enough-token" + ); + tokenContract.approve(cTokenPay, _amt); + require( + cTokenContract.liquidateBorrow(borrower, _amt, cTokenColl) == 0, + "liquidate-failed" + ); + } + setUint(setId, _amt); + + emit LogLiquidate( + address(this), + tokenToPay, + tokenInReturn, + _amt, + getId, + setId + ); + bytes32 _eventCode = keccak256( + "LogLiquidate(address,address,address,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + address(this), + tokenToPay, + tokenInReturn, + _amt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract ConnectCompound is ExtraResolver { + string public name = "Compound-v1.2"; +} diff --git a/contracts/dependencies/InstaDapp/connectors/makerdao.sol b/contracts/dependencies/InstaDapp/connectors/makerdao.sol new file mode 100644 index 0000000..7159b8f --- /dev/null +++ b/contracts/dependencies/InstaDapp/connectors/makerdao.sol @@ -0,0 +1,1121 @@ +pragma solidity ^0.6.0; + +interface TokenInterface { + function approve(address, uint256) external; + + function transfer(address, uint256) external; + + function transferFrom( + address, + address, + uint256 + ) external; + + function deposit() external payable; + + function withdraw(uint256) external; + + function balanceOf(address) external view returns (uint256); +} + +interface ManagerLike { + function cdpCan( + address, + uint256, + address + ) external view returns (uint256); + + function ilks(uint256) external view returns (bytes32); + + function last(address) external view returns (uint256); + + function count(address) external view returns (uint256); + + function owns(uint256) external view returns (address); + + function urns(uint256) external view returns (address); + + function vat() external view returns (address); + + function open(bytes32, address) external returns (uint256); + + function give(uint256, address) external; + + function frob( + uint256, + int256, + int256 + ) external; + + function flux( + uint256, + address, + uint256 + ) external; + + function move( + uint256, + address, + uint256 + ) external; +} + +interface VatLike { + function can(address, address) external view returns (uint256); + + function ilks(bytes32) + external + view + returns ( + uint256, + uint256, + uint256, + uint256, + uint256 + ); + + function dai(address) external view returns (uint256); + + function urns(bytes32, address) external view returns (uint256, uint256); + + function frob( + bytes32, + address, + address, + address, + int256, + int256 + ) external; + + function hope(address) external; + + function move( + address, + address, + uint256 + ) external; + + function gem(bytes32, address) external view returns (uint256); +} + +interface TokenJoinInterface { + function dec() external returns (uint256); + + function gem() external returns (TokenInterface); + + function join(address, uint256) external payable; + + function exit(address, uint256) external; +} + +interface DaiJoinInterface { + function vat() external returns (VatLike); + + function dai() external returns (TokenInterface); + + function join(address, uint256) external payable; + + function exit(address, uint256) external; +} + +interface JugLike { + function drip(bytes32) external returns (uint256); +} + +interface PotLike { + function pie(address) external view returns (uint256); + + function drip() external returns (uint256); + + function join(uint256) external; + + function exit(uint256) external; +} + +interface MemoryInterface { + function getUint(uint256 _id) external returns (uint256 _num); + + function setUint(uint256 _id, uint256 _val) external; +} + +interface InstaMapping { + function gemJoinMapping(bytes32) external view returns (address); +} + +interface EventInterface { + function emitEvent( + uint256 _connectorType, + uint256 _connectorID, + bytes32 _eventCode, + bytes calldata _eventData + ) external; +} + +interface AccountInterface { + function isAuth(address _user) external view returns (bool); +} + +contract DSMath { + uint256 constant RAY = 10**27; + uint256 constant WAD = 10**18; + + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x - y) <= x, "sub-overflow"); + } + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, WAD), y / 2) / y; + } + + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, RAY), y / 2) / y; + } + + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { + z = add(mul(x, y), RAY / 2) / RAY; + } + + function toInt(uint256 x) internal pure returns (int256 y) { + y = int256(x); + require(y >= 0, "int-overflow"); + } + + function toRad(uint256 wad) internal pure returns (uint256 rad) { + rad = mul(wad, 10**27); + } + + function convertTo18(uint256 _dec, uint256 _amt) + internal + pure + returns (uint256 amt) + { + amt = mul(_amt, 10**(18 - _dec)); + } + + function convert18ToDec(uint256 _dec, uint256 _amt) + internal + pure + returns (uint256 amt) + { + amt = (_amt / 10**(18 - _dec)); + } +} + +contract Helpers is DSMath { + /** + * @dev Return ETH Address. + */ + function getAddressETH() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + } + + /** + * @dev Return WETH Address. + */ + function getAddressWETH() internal pure returns (address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + } + + /** + * @dev Return InstAaMemory Address. + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; + } + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint256 getId, uint256 val) + internal + returns (uint256 returnVal) + { + returnVal = getId == 0 + ? val + : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint256 setId, uint256 val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Connector Details + */ + function connectorID() public pure returns (uint256 _type, uint256 _id) { + (_type, _id) = (1, 40); + } +} + +contract MakerMCDAddresses is Helpers { + /** + * @dev Return Maker MCD Manager Address. + */ + function getMcdManager() internal pure returns (address) { + return 0x5ef30b9986345249bc32d8928B7ee64DE9435E39; + } + + /** + * @dev Return Maker MCD DAI Address. + */ + function getMcdDai() internal pure returns (address) { + return 0x6B175474E89094C44Da98b954EedeAC495271d0F; + } + + /** + * @dev Return Maker MCD DAI_Join Address. + */ + function getMcdDaiJoin() internal pure returns (address) { + return 0x9759A6Ac90977b93B58547b4A71c78317f391A28; + } + + /** + * @dev Return Maker MCD Jug Address. + */ + function getMcdJug() internal pure returns (address) { + return 0x19c0976f590D67707E62397C87829d896Dc0f1F1; + } + + /** + * @dev Return Maker MCD Pot Address. + */ + function getMcdPot() internal pure returns (address) { + return 0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7; + } +} + +contract MakerHelpers is MakerMCDAddresses { + /** + * @dev Return InstaMapping Address. + */ + function getMappingAddr() internal pure returns (address) { + return 0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88; + } + + /** + * @dev Return Close Vault Address. + */ + function getGiveAddress() internal pure returns (address) { + return 0x4dD58550eb15190a5B3DfAE28BB14EeC181fC267; + } + + /** + * @dev Get Vault's ilk. + */ + function getVaultData(ManagerLike managerContract, uint256 vault) + internal + view + returns (bytes32 ilk, address urn) + { + ilk = managerContract.ilks(vault); + urn = managerContract.urns(vault); + } + + /** + * @dev Gem Join address is ETH type collateral. + */ + function isEth(address tknAddr) internal pure returns (bool) { + return tknAddr == getAddressWETH() ? true : false; + } + + /** + * @dev Get Vault Debt Amount. + */ + function _getVaultDebt( + address vat, + bytes32 ilk, + address urn + ) internal view returns (uint256 wad) { + (, uint256 rate, , , ) = VatLike(vat).ilks(ilk); + (, uint256 art) = VatLike(vat).urns(ilk, urn); + uint256 dai = VatLike(vat).dai(urn); + + uint256 rad = sub(mul(art, rate), dai); + wad = rad / RAY; + + wad = mul(wad, RAY) < rad ? wad + 1 : wad; + } + + /** + * @dev Get Borrow Amount. + */ + function _getBorrowAmt( + address vat, + address urn, + bytes32 ilk, + uint256 amt + ) internal returns (int256 dart) { + address jug = getMcdJug(); + uint256 rate = JugLike(jug).drip(ilk); + uint256 dai = VatLike(vat).dai(urn); + if (dai < mul(amt, RAY)) { + dart = toInt(sub(mul(amt, RAY), dai) / rate); + dart = mul(uint256(dart), rate) < mul(amt, RAY) ? dart + 1 : dart; + } + } + + /** + * @dev Get Payback Amount. + */ + function _getWipeAmt( + address vat, + uint256 amt, + address urn, + bytes32 ilk + ) internal view returns (int256 dart) { + (, uint256 rate, , , ) = VatLike(vat).ilks(ilk); + (, uint256 art) = VatLike(vat).urns(ilk, urn); + dart = toInt(amt / rate); + dart = uint256(dart) <= art ? -dart : -toInt(art); + } + + /** + * @dev Convert String to bytes32. + */ + function stringToBytes32(string memory str) + internal + pure + returns (bytes32 result) + { + require(bytes(str).length != 0, "string-empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } + + /** + * @dev Get vault ID. If `vault` is 0, get last opened vault. + */ + function getVault(ManagerLike managerContract, uint256 vault) + internal + view + returns (uint256 _vault) + { + if (vault == 0) { + require( + managerContract.count(address(this)) > 0, + "no-vault-opened" + ); + _vault = managerContract.last(address(this)); + } else { + _vault = vault; + } + } +} + +contract EventHelper is MakerHelpers { + event LogOpen(uint256 indexed vault, bytes32 indexed ilk); + event LogClose(uint256 indexed vault, bytes32 indexed ilk); + event LogTransfer( + uint256 indexed vault, + bytes32 indexed ilk, + address newOwner + ); + event LogDeposit( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogWithdraw( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogBorrow( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogPayback( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + function emitLogDeposit( + uint256 vault, + bytes32 ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ) internal { + emit LogDeposit(vault, ilk, tokenAmt, getId, setId); + bytes32 _eventCode = keccak256( + "LogDeposit(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + vault, + ilk, + tokenAmt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + function emitLogBorrow( + uint256 vault, + bytes32 ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ) internal { + emit LogBorrow(vault, ilk, tokenAmt, getId, setId); + bytes32 _eventCode = keccak256( + "LogBorrow(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode( + vault, + ilk, + tokenAmt, + getId, + setId + ); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract BasicResolver is EventHelper { + /** + * @dev Open Vault + * @param colType Type of Collateral.(eg: 'ETH-A') + */ + function open(string calldata colType) + external + payable + returns (uint256 vault) + { + bytes32 ilk = stringToBytes32(colType); + require( + InstaMapping(getMappingAddr()).gemJoinMapping(ilk) != address(0), + "wrong-col-type" + ); + vault = ManagerLike(getMcdManager()).open(ilk, address(this)); + + emit LogOpen(vault, ilk); + bytes32 _eventCode = keccak256("LogOpen(uint256,bytes32)"); + bytes memory _eventParam = abi.encode(vault, ilk); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Close Vault + * @param vault Vault ID to close. + */ + function close(uint256 vault) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + (uint256 ink, uint256 art) = VatLike(managerContract.vat()).urns( + ilk, + urn + ); + + require(ink == 0 && art == 0, "vault-has-assets"); + require(managerContract.owns(_vault) == address(this), "not-owner"); + + managerContract.give(_vault, getGiveAddress()); + + emit LogClose(_vault, ilk); + bytes32 _eventCode = keccak256("LogClose(uint256,bytes32)"); + bytes memory _eventParam = abi.encode(_vault, ilk); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Deposit ETH/ERC20_Token Collateral. + * @param vault Vault ID. + * @param amt token amount to deposit. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function deposit( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _amt = getUint(getId, amt); + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + + address colAddr = InstaMapping(getMappingAddr()).gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + TokenInterface tokenContract = tokenJoinContract.gem(); + + if (isEth(address(tokenContract))) { + _amt = _amt == uint256(-1) ? address(this).balance : _amt; + tokenContract.deposit.value(_amt)(); + } else { + _amt = _amt == uint256(-1) + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + tokenContract.approve(address(colAddr), _amt); + tokenJoinContract.join(address(this), _amt); + + VatLike(managerContract.vat()).frob( + ilk, + urn, + address(this), + address(this), + toInt(convertTo18(tokenJoinContract.dec(), _amt)), + 0 + ); + + setUint(setId, _amt); + + emitLogDeposit(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Withdraw ETH/ERC20_Token Collateral. + * @param vault Vault ID. + * @param amt token amount to withdraw. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function withdraw( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _amt = getUint(getId, amt); + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + + address colAddr = InstaMapping(getMappingAddr()).gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + + uint256 _amt18; + if (_amt == uint256(-1)) { + (_amt18, ) = VatLike(managerContract.vat()).urns(ilk, urn); + _amt = convert18ToDec(tokenJoinContract.dec(), _amt18); + } else { + _amt18 = convertTo18(tokenJoinContract.dec(), _amt); + } + + managerContract.frob(_vault, -toInt(_amt18), 0); + + managerContract.flux(_vault, address(this), _amt18); + + TokenInterface tokenContract = tokenJoinContract.gem(); + + if (isEth(address(tokenContract))) { + tokenJoinContract.exit(address(this), _amt); + tokenContract.withdraw(_amt); + } else { + tokenJoinContract.exit(address(this), _amt); + } + + setUint(setId, _amt); + + emit LogWithdraw(_vault, ilk, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogWithdraw(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Borrow DAI. + * @param vault Vault ID. + * @param amt token amount to borrow. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function borrow( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _amt = getUint(getId, amt); + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + + address daiJoin = getMcdDaiJoin(); + + VatLike vatContract = VatLike(managerContract.vat()); + + managerContract.frob( + _vault, + 0, + _getBorrowAmt(address(vatContract), urn, ilk, _amt) + ); + + managerContract.move(_vault, address(this), toRad(_amt)); + + if (vatContract.can(address(this), address(daiJoin)) == 0) { + vatContract.hope(daiJoin); + } + + DaiJoinInterface(daiJoin).exit(address(this), _amt); + + setUint(setId, _amt); + + emitLogBorrow(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Payback borrowed DAI. + * @param vault Vault ID. + * @param amt token amount to payback. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function payback( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + uint256 _amt = getUint(getId, amt); + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + + address vat = managerContract.vat(); + + uint256 _maxDebt = _getVaultDebt(vat, ilk, urn); + + _amt = _amt == uint256(-1) ? _maxDebt : _amt; + + require(_maxDebt >= _amt, "paying-excess-debt"); + + DaiJoinInterface daiJoinContract = DaiJoinInterface(getMcdDaiJoin()); + daiJoinContract.dai().approve(getMcdDaiJoin(), _amt); + daiJoinContract.join(urn, _amt); + + managerContract.frob( + _vault, + 0, + _getWipeAmt(vat, VatLike(vat).dai(urn), urn, ilk) + ); + + setUint(setId, _amt); + + emit LogPayback(_vault, ilk, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogPayback(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract BasicExtraResolver is BasicResolver { + event LogWithdrawLiquidated( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + event LogExitDai( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + /** + * @dev Withdraw leftover ETH/ERC20_Token after Liquidation. + * @param vault Vault ID. + * @param amt token amount to Withdraw. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function withdrawLiquidated( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _amt = getUint(getId, amt); + (bytes32 ilk, address urn) = getVaultData(managerContract, vault); + + address colAddr = InstaMapping(getMappingAddr()).gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + + uint256 _amt18; + if (_amt == uint256(-1)) { + _amt18 = VatLike(managerContract.vat()).gem(ilk, urn); + _amt = convert18ToDec(tokenJoinContract.dec(), _amt); + } else { + _amt18 = convertTo18(tokenJoinContract.dec(), _amt); + } + + managerContract.flux(vault, address(this), _amt18); + + TokenInterface tokenContract = tokenJoinContract.gem(); + tokenJoinContract.exit(address(this), _amt); + if (isEth(address(tokenContract))) { + tokenContract.withdraw(_amt); + } + + setUint(setId, _amt); + + emit LogWithdrawLiquidated(vault, ilk, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogWithdrawLiquidated(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(vault, ilk, _amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + struct MakerData { + uint256 _vault; + address colAddr; + address daiJoin; + TokenJoinInterface tokenJoinContract; + VatLike vatContract; + TokenInterface tokenContract; + } + + /** + * @dev Deposit ETH/ERC20_Token Collateral and Borrow DAI. + * @param vault Vault ID. + * @param depositAmt token deposit amount to Withdraw. + * @param borrowAmt token borrow amount to Withdraw. + * @param getIdDeposit Get deposit token amount at this ID from `InstaMemory` Contract. + * @param getIdBorrow Get borrow token amount at this ID from `InstaMemory` Contract. + * @param setIdDeposit Set deposit token amount at this ID in `InstaMemory` Contract. + * @param setIdBorrow Set borrow token amount at this ID in `InstaMemory` Contract. + */ + function depositAndBorrow( + uint256 vault, + uint256 depositAmt, + uint256 borrowAmt, + uint256 getIdDeposit, + uint256 getIdBorrow, + uint256 setIdDeposit, + uint256 setIdBorrow + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + MakerData memory makerData; + uint256 _amtDeposit = getUint(getIdDeposit, depositAmt); + uint256 _amtBorrow = getUint(getIdBorrow, borrowAmt); + + makerData._vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData( + managerContract, + makerData._vault + ); + + makerData.colAddr = InstaMapping(getMappingAddr()).gemJoinMapping(ilk); + makerData.tokenJoinContract = TokenJoinInterface(makerData.colAddr); + makerData.vatContract = VatLike(managerContract.vat()); + makerData.daiJoin = getMcdDaiJoin(); + + makerData.tokenContract = makerData.tokenJoinContract.gem(); + + if (isEth(address(makerData.tokenContract))) { + _amtDeposit = _amtDeposit == uint256(-1) + ? address(this).balance + : _amtDeposit; + makerData.tokenContract.deposit.value(_amtDeposit)(); + } else { + _amtDeposit = _amtDeposit == uint256(-1) + ? makerData.tokenContract.balanceOf(address(this)) + : _amtDeposit; + } + + makerData.tokenContract.approve( + address(makerData.colAddr), + _amtDeposit + ); + makerData.tokenJoinContract.join(urn, _amtDeposit); + + managerContract.frob( + makerData._vault, + toInt(convertTo18(makerData.tokenJoinContract.dec(), _amtDeposit)), + _getBorrowAmt(address(makerData.vatContract), urn, ilk, _amtBorrow) + ); + + managerContract.move( + makerData._vault, + address(this), + toRad(_amtBorrow) + ); + + if ( + makerData.vatContract.can( + address(this), + address(makerData.daiJoin) + ) == 0 + ) { + makerData.vatContract.hope(makerData.daiJoin); + } + + DaiJoinInterface(makerData.daiJoin).exit(address(this), _amtBorrow); + + setUint(setIdDeposit, _amtDeposit); + setUint(setIdBorrow, _amtBorrow); + + emitLogDeposit( + makerData._vault, + ilk, + _amtDeposit, + getIdDeposit, + setIdDeposit + ); + + emitLogBorrow( + makerData._vault, + ilk, + _amtBorrow, + getIdBorrow, + setIdBorrow + ); + } + + /** + * @dev Exit DAI from urn. + * @param vault Vault ID. + * @param amt token amount to exit. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function exitDai( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + ManagerLike managerContract = ManagerLike(getMcdManager()); + + uint256 _amt = getUint(getId, amt); + uint256 _vault = getVault(managerContract, vault); + (bytes32 ilk, address urn) = getVaultData(managerContract, _vault); + + address daiJoin = getMcdDaiJoin(); + + VatLike vatContract = VatLike(managerContract.vat()); + if (_amt == uint256(-1)) { + _amt = vatContract.dai(urn); + _amt = _amt / 10**27; + } + + managerContract.move(_vault, address(this), toRad(_amt)); + + if (vatContract.can(address(this), address(daiJoin)) == 0) { + vatContract.hope(daiJoin); + } + + DaiJoinInterface(daiJoin).exit(address(this), _amt); + + setUint(setId, _amt); + + emit LogExitDai(_vault, ilk, _amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogExitDai(uint256,bytes32,uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract DsrResolver is BasicExtraResolver { + event LogDepositDai(uint256 tokenAmt, uint256 getId, uint256 setId); + event LogWithdrawDai(uint256 tokenAmt, uint256 getId, uint256 setId); + + /** + * @dev Deposit DAI in DSR. + * @param amt DAI amount to deposit. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function depositDai( + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + address pot = getMcdPot(); + address daiJoin = getMcdDaiJoin(); + DaiJoinInterface daiJoinContract = DaiJoinInterface(daiJoin); + + _amt = _amt == uint256(-1) + ? daiJoinContract.dai().balanceOf(address(this)) + : _amt; + + VatLike vat = daiJoinContract.vat(); + PotLike potContract = PotLike(pot); + + uint256 chi = potContract.drip(); + + daiJoinContract.dai().approve(daiJoin, _amt); + daiJoinContract.join(address(this), _amt); + if (vat.can(address(this), address(pot)) == 0) { + vat.hope(pot); + } + + potContract.join(mul(_amt, RAY) / chi); + setUint(setId, _amt); + + emit LogDepositDai(_amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogDepositDai(uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } + + /** + * @dev Withdraw DAI from DSR. + * @param amt DAI amount to withdraw. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function withdrawDai( + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + address daiJoin = getMcdDaiJoin(); + + uint256 _amt = getUint(getId, amt); + + DaiJoinInterface daiJoinContract = DaiJoinInterface(daiJoin); + VatLike vat = daiJoinContract.vat(); + PotLike potContract = PotLike(getMcdPot()); + + uint256 chi = potContract.drip(); + uint256 pie; + if (_amt == uint256(-1)) { + pie = potContract.pie(address(this)); + _amt = mul(chi, pie) / RAY; + } else { + pie = mul(_amt, RAY) / chi; + } + + potContract.exit(pie); + + uint256 bal = vat.dai(address(this)); + if (vat.can(address(this), address(daiJoin)) == 0) { + vat.hope(daiJoin); + } + daiJoinContract.exit( + address(this), + bal >= mul(_amt, RAY) ? _amt : bal / RAY + ); + + setUint(setId, _amt); + + emit LogWithdrawDai(_amt, getId, setId); + bytes32 _eventCode = keccak256( + "LogWithdrawDai(uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_amt, getId, setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent( + _type, + _id, + _eventCode, + _eventParam + ); + } +} + +contract ConnectMaker is DsrResolver { + string public constant name = "MakerDao-v1.3"; +} diff --git a/contracts/dependencies/InstaDapp/dsa-contracts/account.sol b/contracts/dependencies/InstaDapp/dsa-contracts/account.sol new file mode 100644 index 0000000..1475545 --- /dev/null +++ b/contracts/dependencies/InstaDapp/dsa-contracts/account.sol @@ -0,0 +1,177 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +/** + * @title InstaAccount. + * @dev DeFi Smart Account Wallet. + */ + +interface IndexInterface { + function connectors(uint256 version) external view returns (address); + + function check(uint256 version) external view returns (address); + + function list() external view returns (address); +} + +interface ConnectorsInterface { + function isConnector(address[] calldata logicAddr) + external + view + returns (bool); + + function isStaticConnector(address[] calldata logicAddr) + external + view + returns (bool); +} + +interface CheckInterface { + function isOk() external view returns (bool); +} + +interface ListInterface { + function addAuth(address user) external; + + function removeAuth(address user) external; +} + +contract Record { + event LogEnable(address indexed user); + event LogDisable(address indexed user); + event LogSwitchShield(bool _shield); + + // InstaIndex Address. + address + public constant instaIndex = 0x0000000000000000000000000000000000000000; + // The Account Module Version. + uint256 public constant version = 1; + // Auth Module(Address of Auth => bool). + mapping(address => bool) private auth; + // Is shield true/false. + bool public shield; + + /** + * @dev Check for Auth if enabled. + * @param user address/user/owner. + */ + function isAuth(address user) public view returns (bool) { + return auth[user]; + } + + /** + * @dev Change Shield State. + */ + function switchShield(bool _shield) external { + require(auth[msg.sender], "not-self"); + require(shield != _shield, "shield is set"); + shield = _shield; + emit LogSwitchShield(shield); + } + + /** + * @dev Enable New User. + * @param user Owner of the Smart Account. + */ + function enable(address user) public { + require( + msg.sender == address(this) || msg.sender == instaIndex, + "not-self-index" + ); + require(user != address(0), "not-valid"); + require(!auth[user], "already-enabled"); + auth[user] = true; + ListInterface(IndexInterface(instaIndex).list()).addAuth(user); + emit LogEnable(user); + } + + /** + * @dev Disable User. + * @param user Owner of the Smart Account. + */ + function disable(address user) public { + require(msg.sender == address(this), "not-self"); + require(user != address(0), "not-valid"); + require(auth[user], "already-disabled"); + delete auth[user]; + ListInterface(IndexInterface(instaIndex).list()).removeAuth(user); + emit LogDisable(user); + } +} + +contract InstaAccount is Record { + event LogCast( + address indexed origin, + address indexed sender, + uint256 value + ); + + receive() external payable {} + + /** + * @dev Delegate the calls to Connector And this function is ran by cast(). + * @param _target Target to of Connector. + * @param _data CallData of function in Connector. + */ + function spell(address _target, bytes memory _data) internal { + require(_target != address(0), "target-invalid"); + assembly { + let succeeded := delegatecall( + gas(), + _target, + add(_data, 0x20), + mload(_data), + 0, + 0 + ) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + let size := returndatasize() + returndatacopy(0x00, 0x00, size) + revert(0x00, size) + } + } + } + + /** + * @dev This is the main function, Where all the different functions are called + * from Smart Account. + * @param _targets Array of Target(s) to of Connector. + * @param _datas Array of Calldata(S) of function. + */ + function cast( + address[] calldata _targets, + bytes[] calldata _datas, + address _origin + ) external payable { + require( + isAuth(msg.sender) || msg.sender == instaIndex, + "permission-denied" + ); + require(_targets.length == _datas.length, "array-length-invalid"); + IndexInterface indexContract = IndexInterface(instaIndex); + bool isShield = shield; + if (!isShield) { + require( + ConnectorsInterface(indexContract.connectors(version)) + .isConnector(_targets), + "not-connector" + ); + } else { + require( + ConnectorsInterface(indexContract.connectors(version)) + .isStaticConnector(_targets), + "not-static-connector" + ); + } + for (uint256 i = 0; i < _targets.length; i++) { + spell(_targets[i], _datas[i]); + } + address _check = indexContract.check(version); + if (_check != address(0) && !isShield) + require(CheckInterface(_check).isOk(), "not-ok"); + emit LogCast(_origin, msg.sender, msg.value); + } +} diff --git a/contracts/dependencies/InstaDapp/dsa-contracts/connectors.sol b/contracts/dependencies/InstaDapp/dsa-contracts/connectors.sol new file mode 100644 index 0000000..5b99417 --- /dev/null +++ b/contracts/dependencies/InstaDapp/dsa-contracts/connectors.sol @@ -0,0 +1,200 @@ +pragma solidity ^0.6.0; + +/** + * @title InstaConnectors + * @dev Registry for Connectors. + */ + +interface IndexInterface { + function master() external view returns (address); +} + +interface ConnectorInterface { + function connectorID() external view returns (uint256 _type, uint256 _id); + + function name() external view returns (string memory); +} + +contract DSMath { + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x + y) >= x, "ds-math-add-overflow"); + } + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } +} + +contract Controllers is DSMath { + event LogAddController(address indexed addr); + event LogRemoveController(address indexed addr); + + // InstaIndex Address. + address + public constant instaIndex = 0x0000000000000000000000000000000000000000; + + // Enabled Chief(Address of Chief => bool). + mapping(address => bool) public chief; + // Enabled Connectors(Connector Address => bool). + mapping(address => bool) public connectors; + // Enabled Static Connectors(Connector Address => bool). + mapping(address => bool) public staticConnectors; + + /** + * @dev Throws if the sender not is Master Address from InstaIndex + * or Enabled Chief. + */ + modifier isChief { + require( + chief[msg.sender] || + msg.sender == IndexInterface(instaIndex).master(), + "not-an-chief" + ); + _; + } + + /** + * @dev Enable a Chief. + * @param _userAddress Chief Address. + */ + function enableChief(address _userAddress) external isChief { + chief[_userAddress] = true; + emit LogAddController(_userAddress); + } + + /** + * @dev Disables a Chief. + * @param _userAddress Chief Address. + */ + function disableChief(address _userAddress) external isChief { + delete chief[_userAddress]; + emit LogRemoveController(_userAddress); + } +} + +contract Listings is Controllers { + // Connectors Array. + address[] public connectorArray; + // Count of Connector's Enabled. + uint256 public connectorCount; + + /** + * @dev Add Connector to Connector's array. + * @param _connector Connector Address. + **/ + function addToArr(address _connector) internal { + require(_connector != address(0), "Not-valid-connector"); + (, uint256 _id) = ConnectorInterface(_connector).connectorID(); + require(_id == (connectorArray.length + 1), "ConnectorID-doesnt-match"); + ConnectorInterface(_connector).name(); // Checking if connector has function name() + connectorArray.push(_connector); + } + + // Static Connectors Array. + address[] public staticConnectorArray; + + /** + * @dev Add Connector to Static Connector's array. + * @param _connector Static Connector Address. + **/ + function addToArrStatic(address _connector) internal { + require(_connector != address(0), "Not-valid-connector"); + (, uint256 _id) = ConnectorInterface(_connector).connectorID(); + require( + _id == (staticConnectorArray.length + 1), + "ConnectorID-doesnt-match" + ); + ConnectorInterface(_connector).name(); // Checking if connector has function name() + staticConnectorArray.push(_connector); + } +} + +contract InstaConnectors is Listings { + event LogEnable(address indexed connector); + event LogDisable(address indexed connector); + event LogEnableStatic(address indexed connector); + + /** + * @dev Enable Connector. + * @param _connector Connector Address. + */ + function enable(address _connector) external isChief { + require(!connectors[_connector], "already-enabled"); + addToArr(_connector); + connectors[_connector] = true; + connectorCount++; + emit LogEnable(_connector); + } + + /** + * @dev Disable Connector. + * @param _connector Connector Address. + */ + function disable(address _connector) external isChief { + require(connectors[_connector], "already-disabled"); + delete connectors[_connector]; + connectorCount--; + emit LogDisable(_connector); + } + + /** + * @dev Enable Static Connector. + * @param _connector Static Connector Address. + */ + function enableStatic(address _connector) external isChief { + require(!staticConnectors[_connector], "already-enabled"); + addToArrStatic(_connector); + staticConnectors[_connector] = true; + emit LogEnableStatic(_connector); + } + + /** + * @dev Check if Connector addresses are enabled. + * @param _connectors Array of Connector Addresses. + */ + function isConnector(address[] calldata _connectors) + external + view + returns (bool isOk) + { + isOk = true; + for (uint256 i = 0; i < _connectors.length; i++) { + if (!connectors[_connectors[i]]) { + isOk = false; + break; + } + } + } + + /** + * @dev Check if Connector addresses are static enabled. + * @param _connectors Array of Connector Addresses. + */ + function isStaticConnector(address[] calldata _connectors) + external + view + returns (bool isOk) + { + isOk = true; + for (uint256 i = 0; i < _connectors.length; i++) { + if (!staticConnectors[_connectors[i]]) { + isOk = false; + break; + } + } + } + + /** + * @dev get Connector's Array length. + */ + function connectorLength() external view returns (uint256) { + return connectorArray.length; + } + + /** + * @dev get Static Connector's Array length. + */ + function staticConnectorLength() external view returns (uint256) { + return staticConnectorArray.length; + } +} diff --git a/contracts/dependencies/InstaDapp/dsa-contracts/index.sol b/contracts/dependencies/InstaDapp/dsa-contracts/index.sol new file mode 100644 index 0000000..24113f3 --- /dev/null +++ b/contracts/dependencies/InstaDapp/dsa-contracts/index.sol @@ -0,0 +1,255 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +/** + * @title InstaIndex + * @dev Main Contract For DeFi Smart Accounts. This is also a factory contract, Which deploys new Smart Account. + * Also Registry for DeFi Smart Accounts. + */ + +interface AccountInterface { + function version() external view returns (uint256); + + function enable(address authority) external; + + function cast( + address[] calldata _targets, + bytes[] calldata _datas, + address _origin + ) external payable returns (bytes32[] memory responses); +} + +interface ListInterface { + function init(address _account) external; +} + +contract AddressIndex { + event LogNewMaster(address indexed master); + event LogUpdateMaster(address indexed master); + event LogNewCheck(uint256 indexed accountVersion, address indexed check); + event LogNewAccount( + address indexed _newAccount, + address indexed _connectors, + address indexed _check + ); + + // New Master Address. + address private newMaster; + // Master Address. + address public master; + // List Registry Address. + address public list; + + // Connectors Modules(Account Module Version => Connectors Registry Module Address). + mapping(uint256 => address) public connectors; + // Check Modules(Account Module Version => Check Module Address). + mapping(uint256 => address) public check; + // Account Modules(Account Module Version => Account Module Address). + mapping(uint256 => address) public account; + // Version Count of Account Modules. + uint256 public versionCount; + + /** + * @dev Throws if the sender not is Master Address. + */ + modifier isMaster() { + require(msg.sender == master, "not-master"); + _; + } + + /** + * @dev Change the Master Address. + * @param _newMaster New Master Address. + */ + function changeMaster(address _newMaster) external isMaster { + require(_newMaster != master, "already-a-master"); + require(_newMaster != address(0), "not-valid-address"); + require(newMaster != _newMaster, "already-a-new-master"); + newMaster = _newMaster; + emit LogNewMaster(_newMaster); + } + + function updateMaster() external { + require(newMaster != address(0), "not-valid-address"); + require(msg.sender == newMaster, "not-master"); + master = newMaster; + newMaster = address(0); + emit LogUpdateMaster(master); + } + + /** + * @dev Change the Check Address of a specific Account Module version. + * @param accountVersion Account Module version. + * @param _newCheck The New Check Address. + */ + function changeCheck(uint256 accountVersion, address _newCheck) + external + isMaster + { + require(_newCheck != check[accountVersion], "already-a-check"); + check[accountVersion] = _newCheck; + emit LogNewCheck(accountVersion, _newCheck); + } + + /** + * @dev Add New Account Module. + * @param _newAccount The New Account Module Address. + * @param _connectors Connectors Registry Module Address. + * @param _check Check Module Address. + */ + function addNewAccount( + address _newAccount, + address _connectors, + address _check + ) external isMaster { + require(_newAccount != address(0), "not-valid-address"); + versionCount++; + require( + AccountInterface(_newAccount).version() == versionCount, + "not-valid-version" + ); + account[versionCount] = _newAccount; + if (_connectors != address(0)) connectors[versionCount] = _connectors; + if (_check != address(0)) check[versionCount] = _check; + emit LogNewAccount(_newAccount, _connectors, _check); + } +} + +contract CloneFactory is AddressIndex { + /** + * @dev Clone a new Account Module. + * @param version Account Module version to clone. + */ + function createClone(uint256 version) internal returns (address result) { + bytes20 targetBytes = bytes20(account[version]); + // solium-disable-next-line security/no-inline-assembly + assembly { + let clone := mload(0x40) + mstore( + clone, + 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000 + ) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + result := create(0, clone, 0x37) + } + } + + /** + * @dev Check if Account Module is a clone. + * @param version Account Module version. + * @param query Account Module Address. + */ + function isClone(uint256 version, address query) + external + view + returns (bool result) + { + bytes20 targetBytes = bytes20(account[version]); + // solium-disable-next-line security/no-inline-assembly + assembly { + let clone := mload(0x40) + mstore( + clone, + 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000 + ) + mstore(add(clone, 0xa), targetBytes) + mstore( + add(clone, 0x1e), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + + let other := add(clone, 0x40) + extcodecopy(query, other, 0, 0x2d) + result := and( + eq(mload(clone), mload(other)), + eq(mload(add(clone, 0xd)), mload(add(other, 0xd))) + ) + } + } +} + +contract InstaIndex is CloneFactory { + event LogAccountCreated( + address sender, + address indexed owner, + address indexed account, + address indexed origin + ); + + /** + * @dev Create a new DeFi Smart Account for a user and run cast function in the new Smart Account. + * @param _owner Owner of the Smart Account. + * @param accountVersion Account Module version. + * @param _targets Array of Target to run cast function. + * @param _datas Array of Data(callData) to run cast function. + * @param _origin Where Smart Account is created. + */ + function buildWithCast( + address _owner, + uint256 accountVersion, + address[] calldata _targets, + bytes[] calldata _datas, + address _origin + ) external payable returns (address _account) { + _account = build(_owner, accountVersion, _origin); + if (_targets.length > 0) + AccountInterface(_account).cast.value(msg.value)( + _targets, + _datas, + _origin + ); + } + + /** + * @dev Create a new DeFi Smart Account for a user. + * @param _owner Owner of the Smart Account. + * @param accountVersion Account Module version. + * @param _origin Where Smart Account is created. + */ + function build( + address _owner, + uint256 accountVersion, + address _origin + ) public returns (address _account) { + require( + accountVersion != 0 && accountVersion <= versionCount, + "not-valid-account" + ); + _account = createClone(accountVersion); + ListInterface(list).init(_account); + AccountInterface(_account).enable(_owner); + emit LogAccountCreated(msg.sender, _owner, _account, _origin); + } + + /** + * @dev Setup Initial things for InstaIndex, after its been deployed and can be only run once. + * @param _master The Master Address. + * @param _list The List Address. + * @param _account The Account Module Address. + * @param _connectors The Connectors Registry Module Address. + */ + function setBasics( + address _master, + address _list, + address _account, + address _connectors + ) external { + require( + master == address(0) && + list == address(0) && + account[1] == address(0) && + connectors[1] == address(0) && + versionCount == 0, + "already-defined" + ); + master = _master; + list = _list; + versionCount++; + account[versionCount] = _account; + connectors[versionCount] = _connectors; + } +} diff --git a/contracts/dependencies/InstaDapp/dsa-contracts/list.sol b/contracts/dependencies/InstaDapp/dsa-contracts/list.sol new file mode 100644 index 0000000..c556711 --- /dev/null +++ b/contracts/dependencies/InstaDapp/dsa-contracts/list.sol @@ -0,0 +1,163 @@ +pragma solidity ^0.6.0; + +/** + * @title InstaList + * @dev Registry For DeFi Smart Account Authorised user. + */ + +interface AccountInterface { + function isAuth(address _user) external view returns (bool); +} + +contract DSMath { + function add(uint64 x, uint64 y) internal pure returns (uint64 z) { + require((z = x + y) >= x, "ds-math-add-overflow"); + } + + function sub(uint64 x, uint64 y) internal pure returns (uint64 z) { + require((z = x - y) <= x, "ds-math-sub-underflow"); + } +} + +contract Variables is DSMath { + // InstaIndex Address. + address + public constant instaIndex = 0x0000000000000000000000000000000000000000; + + // Smart Account Count. + uint64 public accounts; + // Smart Account ID (Smart Account Address => Account ID). + mapping(address => uint64) public accountID; + // Smart Account Address (Smart Account ID => Smart Account Address). + mapping(uint64 => address) public accountAddr; + + // User Link (User Address => UserLink(Account ID of First and Last And Count of Smart Accounts)). + mapping(address => UserLink) public userLink; + // Linked List of Users (User Address => Smart Account ID => UserList(Previous and next Account ID)). + mapping(address => mapping(uint64 => UserList)) public userList; + + struct UserLink { + uint64 first; + uint64 last; + uint64 count; + } + struct UserList { + uint64 prev; + uint64 next; + } + + // Account Link (Smart Account ID => AccountLink). + mapping(uint64 => AccountLink) public accountLink; // account => account linked list connection + // Linked List of Accounts (Smart Account ID => Account Address => AccountList). + mapping(uint64 => mapping(address => AccountList)) public accountList; // account => user address => list + + struct AccountLink { + address first; + address last; + uint64 count; + } + struct AccountList { + address prev; + address next; + } +} + +contract Configure is Variables { + /** + * @dev Add Account to User Linked List. + * @param _owner Account Owner. + * @param _account Smart Account Address. + */ + function addAccount(address _owner, uint64 _account) internal { + if (userLink[_owner].last != 0) { + userList[_owner][_account].prev = userLink[_owner].last; + userList[_owner][userLink[_owner].last].next = _account; + } + if (userLink[_owner].first == 0) userLink[_owner].first = _account; + userLink[_owner].last = _account; + userLink[_owner].count = add(userLink[_owner].count, 1); + } + + /** + * @dev Remove Account from User Linked List. + * @param _owner Account Owner/User. + * @param _account Smart Account Address. + */ + function removeAccount(address _owner, uint64 _account) internal { + uint64 _prev = userList[_owner][_account].prev; + uint64 _next = userList[_owner][_account].next; + if (_prev != 0) userList[_owner][_prev].next = _next; + if (_next != 0) userList[_owner][_next].prev = _prev; + if (_prev == 0) userLink[_owner].first = _next; + if (_next == 0) userLink[_owner].last = _prev; + userLink[_owner].count = sub(userLink[_owner].count, 1); + delete userList[_owner][_account]; + } + + /** + * @dev Add Owner to Account Linked List. + * @param _owner Account Owner. + * @param _account Smart Account Address. + */ + function addUser(address _owner, uint64 _account) internal { + if (accountLink[_account].last != address(0)) { + accountList[_account][_owner].prev = accountLink[_account].last; + accountList[_account][accountLink[_account].last].next = _owner; + } + if (accountLink[_account].first == address(0)) + accountLink[_account].first = _owner; + accountLink[_account].last = _owner; + accountLink[_account].count = add(accountLink[_account].count, 1); + } + + /** + * @dev Remove Owner from Account Linked List. + * @param _owner Account Owner. + * @param _account Smart Account Address. + */ + function removeUser(address _owner, uint64 _account) internal { + address _prev = accountList[_account][_owner].prev; + address _next = accountList[_account][_owner].next; + if (_prev != address(0)) accountList[_account][_prev].next = _next; + if (_next != address(0)) accountList[_account][_next].prev = _prev; + if (_prev == address(0)) accountLink[_account].first = _next; + if (_next == address(0)) accountLink[_account].last = _prev; + accountLink[_account].count = sub(accountLink[_account].count, 1); + delete accountList[_account][_owner]; + } +} + +contract InstaList is Configure { + /** + * @dev Enable Auth for Smart Account. + * @param _owner Owner Address. + */ + function addAuth(address _owner) external { + require(accountID[msg.sender] != 0, "not-account"); + require(AccountInterface(msg.sender).isAuth(_owner), "not-owner"); + addAccount(_owner, accountID[msg.sender]); + addUser(_owner, accountID[msg.sender]); + } + + /** + * @dev Disable Auth for Smart Account. + * @param _owner Owner Address. + */ + function removeAuth(address _owner) external { + require(accountID[msg.sender] != 0, "not-account"); + require(!AccountInterface(msg.sender).isAuth(_owner), "already-owner"); + removeAccount(_owner, accountID[msg.sender]); + removeUser(_owner, accountID[msg.sender]); + } + + /** + * @dev Setup Initial configuration of Smart Account. + * @param _account Smart Account Address. + */ + function init(address _account) external { + require(msg.sender == instaIndex, "not-index"); + accounts++; + accountID[_account] = accounts; + accountAddr[accounts] = _account; + } +} diff --git a/hardhat.config.js b/hardhat.config.js index 3cdf036..7b39f28 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -91,10 +91,40 @@ module.exports = { }, }, solidity: { - version: "0.7.4", - settings: { - optimizer: {enabled: process.env.DEBUG ? false : true}, - }, + compilers: [ + { + version: "0.6.10", + settings: { + optimizer: {enabled: process.env.DEBUG ? false : true}, + }, + }, + { + version: "0.7.4", + settings: { + optimizer: {enabled: process.env.DEBUG ? false : true}, + }, + }, + ], + // overrides: { + // "contracts/vendor/DependenciesSix.sol": { + // version: "0.6.10", + // settings: { + // optimizer: {enabled: process.env.DEBUG ? false : true}, + // }, + // }, + // "@gelatonetwork/core/contracts/gelato_core/GelatoCore.sol": { + // version: "0.6.10", + // settings: { + // optimizer: {enabled: process.env.DEBUG ? false : true}, + // }, + // }, + // "@gelatonetwork/core/contracts/external/Ownable.sol": { + // version: "0.6.10", + // settings: { + // optimizer: {enabled: process.env.DEBUG ? false : true}, + // }, + // }, + // }, }, }; diff --git a/package.json b/package.json index 2fc11fe..5fe2402 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "debug": "DEBUG=true yarn compile && npx hardhat test" }, "devDependencies": { - "@codechecks/client": "^0.1.10", - "@gelatonetwork/core": "1.0.0", + "@codechecks/client": "0.1.10", + "@gelatonetwork/core": "1.3.1", "@nomiclabs/hardhat-ethers": "2.0.0", "@nomiclabs/hardhat-waffle": "2.0.0", "chai": "4.2.0", @@ -28,8 +28,8 @@ "ethers": "5.0.19", "hardhat": "2.0.2", "hardhat-deploy": "0.7.0-beta.28", - "hardhat-deploy-ethers": "^0.3.0-beta.5", - "hardhat-gas-reporter": "^1.0.1", + "hardhat-deploy-ethers": "0.3.0-beta.5", + "hardhat-gas-reporter": "1.0.1", "husky": ">=4", "lint-staged": "10.5.1", "prettier": "2.1.2", diff --git a/yarn.lock b/yarn.lock index fc952c7..37fdd31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,7 +23,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@codechecks/client@^0.1.10": +"@codechecks/client@0.1.10": version "0.1.10" resolved "https://registry.yarnpkg.com/@codechecks/client/-/client-0.1.10.tgz#41fe736c424976d9feb8116b131fb9c1f099d105" integrity sha512-rvX+LknmMohsLTU8mHJqIcNTo8fKfw6A5i7JvT6JJWqwCLi+TujHpRO8BLf48iF96+gU5viVvKfRaUyhc3wloA== @@ -550,10 +550,10 @@ "@ethersproject/properties" "^5.0.3" "@ethersproject/strings" "^5.0.4" -"@gelatonetwork/core@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@gelatonetwork/core/-/core-1.0.0.tgz#57caedca0a19c945f509fc714358ab695aec7909" - integrity sha512-VuN+bVD8w+X/zwfFDOZHivuNOnzIHhHU0nYj8KJ01toFRnX6ABX428xUOO73mRQsiPVhmRxTu3eBBn9roWaNJw== +"@gelatonetwork/core@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@gelatonetwork/core/-/core-1.3.1.tgz#cff0cb4d06a2bbb7859f3918995f44efc692bb11" + integrity sha512-xnl9jskZfAwwaJlIxmiXI+Cm1eKnPoDDBbMPlkNJ2NCDxoDOq/6tjHm9VXIVPDTjpqmNSPzQJjDxFWDrKUrosQ== "@nomiclabs/ethereumjs-vm@^4.1.1": version "4.2.0" @@ -4448,7 +4448,7 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" -hardhat-deploy-ethers@^0.3.0-beta.5: +hardhat-deploy-ethers@0.3.0-beta.5: version "0.3.0-beta.5" resolved "https://registry.yarnpkg.com/hardhat-deploy-ethers/-/hardhat-deploy-ethers-0.3.0-beta.5.tgz#c365ebb5c29e7474b2b35912f27dc9699a0e63b3" integrity sha512-KoUswkCPSuARGjZQIf8kItL5rPFt6srgVj+q0B9YTQ7Vyw/k2N0R8u7aYWq4Piy9mjDKcEGQTPBXhaX02BMkVw== @@ -4478,7 +4478,7 @@ hardhat-deploy@0.7.0-beta.28: murmur-128 "^0.2.1" qs "^6.9.4" -hardhat-gas-reporter@^1.0.1: +hardhat-gas-reporter@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.1.tgz#37f96da5f11e5ae34b28a68c5d972d3168165c95" integrity sha512-YC+SCYIkBdRtISNbisU2BwDSelUdCrIKRsJXt3M9Jw1VF5CmtSZb8VuuOc2Zl4AMcEV2jEy6ZuAksYomPiApYQ==