Borrow
Learn how to borrow through Morpho, onchain via a smart contract & offchain via ethers.js.
Morpho AaveV2 Optimizer & Morpho CompoundV2 Optimizer allow anyone to borrow from any open market and potentially benefit from lower rates via automatic matching, offchain through Etherscan or with ethers.js, or onchain using a smart contract. Here are concrete examples 👇
Morpho AaveV2 Optimizer​
- Solidity
- ethers.js
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.16;
import {IMorpho} from "@morpho-org/morpho-core-v1/contracts/compound/interfaces/IMorpho.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 {
function withdraw(uint256) external;
}
contract MorphoAaveV2Borrower {
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant AWETH = 0x030bA81f1c18d280636F32af80b9AAd02Cf0854e;
address public constant ADAI = 0x028171bCA77440897B824Ca71D1c56caC55b68A3;
address public constant MORPHO = 0x777777c9898D384F785Ee44Acfe945efDFf5f3E0;
function _borrowERC20(address _aToken, uint256 _amount) internal {
IMorpho(MORPHO).borrow(_aToken, _amount);
}
function borrowDAI(uint256 _amount) public {
_borrowERC20(
ADAI, // the DAI market, represented by the aDAI ERC20 token
_amount
);
// this contract now has _amount DAI: IERC20(DAI).balanceOf(address(this)) == _amount
}
function borrowETH(uint256 _amount) public {
_borrowERC20(
AWETH, // the ETH market, represented by the aWETH ERC20 token
_amount
);
// this contract now has _amount WETH: IERC20(WETH).balanceOf(address(this)) == _amount
IWETH9(WETH).withdraw(_amount);
// this contract now has _amount ETH: address(this).balance == _amount
}
}
import ethers from "ethers";
const signer = new ethers.Wallet(
process.env.PRIVATE_KEY,
new ethers.providers.JsonRpcBatchProvider(process.env.RPC_URL)
);
const signerAddress = await signer.getAddress();
const aWethAddress = "0x030bA81f1c18d280636F32af80b9AAd02Cf0854e";
const aDaiAddress = "0x028171bCA77440897B824Ca71D1c56caC55b68A3";
const daiDecimals = 18;
const weth = new ethers.Contract(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
["function withdraw(uint256) external"],
signer
);
const morpho = new ethers.Contract(
"0x777777c9898d384f785ee44acfe945efdff5f3e0",
[
"function borrow(address, uint256) external",
"function borrow(address, uint256, uint256) external",
],
signer
);
async function borrowERC20(aTokenAddress, amount) {
await morpho.borrow(aTokenAddress, amount);
}
async function borrowDAI(amount) {
return borrowERC20(
aDaiAddress, // the DAI market, represented by the aDAI ERC20 token
amount
);
// signer now has _amount DAI: dai.balanceOf(signerAddress) == _amount
}
async function borrowETH(amount) {
await borrowERC20(
aWethAddress, // the WETH market, represented by the cETH ERC20 token
amount
);
// signer now has _amount WETH: weth.balanceOf(signerAddress) == _amount
return weth.withdraw(amount);
// signer now has _amount ETH: signer.getBalance() == _amount
}
// borrowDAI(ethers.utils.parseUnits("100", daiDecimals));
// borrowETH(ethers.utils.parseEther(1));
Morpho CompoundV2 Optimizer​
- Solidity
- ethers.js
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.16;
import {IMorpho} from "@morpho-org/morpho-core-v1/contracts/compound/interfaces/IMorpho.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 {
function withdraw(uint256) external;
}
contract MorphoCompoundBorrower {
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant CETH = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5;
address public constant CDAI = 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643;
address public constant MORPHO = 0x8888882f8f843896699869179fB6E4f7e3B58888;
function _borrowERC20(address _cToken, uint256 _amount) internal {
IMorpho(MORPHO).borrow(_cToken, _amount);
}
function borrowDAI(uint256 _amount) external {
_borrowERC20(
CDAI, // the DAI market, represented by the cDAI ERC20 token
_amount
);
// this contract now has _amount DAI: IERC20(DAI).balanceOf(address(this)) == _amount
}
function borrowETH(uint256 _amount) external {
_borrowERC20(
CETH, // the ETH market, represented by the cETH ERC20 token
_amount
);
// this contract now has _amount WETH: IERC20(WETH).balanceOf(address(this)) == _amount
IWETH9(WETH).withdraw(_amount);
// this contract now has _amount ETH: address(this).balance == _amount
}
}
import ethers from "ethers";
const signer = new ethers.Wallet(
process.env.PRIVATE_KEY,
new ethers.providers.JsonRpcBatchProvider(process.env.RPC_URL)
);
const signerAddress = await signer.getAddress();
const cEthAddress = "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5";
const cDaiAddress = "0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643";
const daiDecimals = 18;
const weth = new ethers.Contract(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
["function withdraw(uint256) external"],
signer
);
const morpho = new ethers.Contract(
"0x8888882f8f843896699869179fB6E4f7e3B58888",
[
"function borrow(address, uint256) external",
"function borrow(address, uint256, uint256) external",
],
signer
);
async function borrowERC20(cTokenAddress, amount) {
await morpho.borrow(cTokenAddress, amount);
}
async function borrowDAI(amount) {
return borrowERC20(
cDaiAddress, // the DAI market, represented by the cDAI ERC20 token
amount
);
// signer now has _amount DAI: dai.balanceOf(signerAddress) == _amount
}
async function borrowETH(amount) {
await borrowERC20(
cEthAddress, // the WETH market, represented by the cETH ERC20 token
amount
);
// signer now has _amount WETH: weth.balanceOf(signerAddress) == _amount
return weth.withdraw(amount);
// signer now has _amount ETH: signer.getBalance() == _amount
}
// borrowDAI(ethers.utils.parseUnits("100", daiDecimals));
// borrowETH(ethers.utils.parseEther(1));