Skip to content

Commit ddd3c5a

Browse files
committed
feat: supplyBorrow
1 parent f701fe5 commit ddd3c5a

File tree

2 files changed

+94
-24
lines changed

2 files changed

+94
-24
lines changed

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,34 @@ are effectively MEV, you can do some really interesting things with them. Like
1414
- Impress your friends
1515
- And more!
1616

17-
[MevWallet]: https://github.com/blunt-instruments/MevWallet
18-
[Signet Orders]: https://signet.sh/docs/learn-about-signet/cross-chain-transfers/
17+
## App Examples
18+
19+
- [`Morpho.sol`](./src/examples/Morpho.sol) - Contracts that allow you to drive
20+
Morpho lending market positions using Signet Orders. This allows you to
21+
supply, borrow, and lend Morpho positions on Ethereum from Signet instantly
22+
and atomically.
1923

20-
## Main Examples
24+
## Orders Examples
2125

2226
- [`SignetStd.sol`](./src/SignetStd.sol) - A simple contract that
2327
auto-configures Signet system parameters, based on the chain id.
2428
- [`Flash.sol`](./src/examples/Flash.sol) - Allows your contract to flash borrow
25-
any asset (provided some searcher will provide it). Flash loans work by having an input and output of the same asset. The Output is then used as the Input to its own Order. This is pretty neat 🎀
29+
any asset (provided some searcher will provide it). Flash loans work by
30+
having an input and output of the same asset. The Output is then used as the
31+
Input to its own Order. This is pretty neat 🎀
2632
- [`GetOut.sol`](./src/examples/GetOut.sol) - A shortcut contract for
2733
exiting Signet (by offering searchers a 50 bps fee).
2834
- [`PayMe.sol`](./src/examples/PayMe.sol) - Payment gating for smart contracts,
29-
using a Signet Order with no inputs. These ensures that contract execution is invalid unless SOMEONE has filled the Order. Unlike traditional payment gates that check `msg.value`, this does NOT require the calling contract to manage cash flow. Instead _any third party_ can fill the order. The calling contract can be blind to the payment. This greatly simplifies contract logic required
35+
using a Signet Order with no inputs. These ensures that contract execution is
36+
invalid unless SOMEONE has filled the Order. Unlike traditional payment gates
37+
that check `msg.value`, this does NOT require the calling contract to manage
38+
cash flow. Instead _any third party_ can fill the order. The calling contract
39+
can be blind to the payment. This greatly simplifies contract logic required
3040
to implement payment gates.
3141
- [`PayYou.sol`](./src/examples/PayYou.sol) - The opposite of payment gating,
32-
this allows a contract to generate MEV by offering a Signet Order with no outputs. This payment becomes a bounty for calling the contract, and functions as an incentivized scheduling system.
42+
this allows a contract to generate MEV by offering a Signet Order with no
43+
outputs. This payment becomes a bounty for calling the contract, and
44+
functions as an incentivized scheduling system.
3345

3446
## Basic Repo Instructions
3547

@@ -50,3 +62,6 @@ $ forge test
5062
```shell
5163
$ forge fmt
5264
```
65+
66+
[MevWallet]: https://github.com/blunt-instruments/MevWallet
67+
[Signet Orders]: https://signet.sh/docs/learn-about-signet/cross-chain-transfers/

src/apps/Morpho.sol

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {IMorpho, MarketParams} from "../interfaces/IMorpho.sol";
55
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
66
import {SignetStd} from "../SignetStd.sol";
77
import {RollupOrders} from "zenith/src/orders/RollupOrders.sol";
8+
import {Passage} from "zenith/src/passage/Passage.sol";
89

910
// How this works:
1011
// - The Signet Orders system calls `transferFrom` and check for the presence
@@ -41,45 +42,58 @@ contract UseMorpho is SignetStd {
4142
/// @dev Address of the shortcut on the host chain.
4243
address immutable repayShortcut;
4344
address immutable supplyShortcut;
45+
address immutable borrowShortcut;
4446

4547
address immutable hostLoanToken;
4648
address immutable hostCollateralToken;
4749

48-
IERC20 immutable loanToken;
49-
IERC20 immutable collateralToken;
50+
IERC20 immutable ruLoanToken;
51+
IERC20 immutable ruCollateralToken;
5052

51-
constructor(address _shortcut, address _hostLoan, address _hostCollateral) SignetStd() {
52-
// The address of the shortcut contract should be well-known.
53-
shortcut = _shortcut;
53+
constructor(address _repayShortcut, address _supplyShortcut, address _hostLoan, address _hostCollateral)
54+
SignetStd()
55+
{
56+
repayShortcut = _repayShortcut;
57+
supplyShortcut = _supplyShortcut;
5458

5559
// Autodetect rollup tokens based on token addresses on host network.
5660
hostLoanToken = _hostLoan;
5761
hostCollateralToken = _hostCollateral;
5862
if (_hostLoan == HOST_WETH) {
59-
loanToken = WETH;
63+
ruLoanToken = WETH;
6064
} else if (_hostLoan == HOST_WBTC) {
61-
loanToken = WBTC;
65+
ruLoanToken = WBTC;
6266
} else if (_hostLoan == HOST_USDC || _hostLoan == HOST_USDT) {
63-
loanToken = WUSD;
67+
ruLoanToken = WUSD;
6468
} else {
6569
revert("Unsupported loan token");
6670
}
71+
if (_hostCollateral == HOST_WETH) {
72+
ruCollateralToken = WETH;
73+
} else if (_hostCollateral == HOST_WBTC) {
74+
ruCollateralToken = WBTC;
75+
} else if (_hostCollateral == HOST_USDC || _hostCollateral == HOST_USDT) {
76+
ruCollateralToken = WUSD;
77+
} else {
78+
revert("Unsupported collateral token");
79+
}
6780

6881
// Pre-emptively approve the Orders contract to spend our tokens.
69-
loanToken.approve(address(ORDERS), type(uint256).max);
70-
collateralToken.approve(address(ORDERS), type(uint256).max);
82+
ruLoanToken.approve(address(ORDERS), type(uint256).max);
83+
ruCollateralToken.approve(address(ORDERS), type(uint256).max);
7184
}
7285

73-
function supply(address onBehalf, uint256 amount) external {
86+
// Supply some amount of the collateral token on behalf of the user.
87+
function supplyCollateral(address onBehalf, uint256 amount) public {
7488
if (amount > 0) {
75-
collateralToken.transferFrom(msg.sender, address(this), amount);
89+
ruCollateralToken.transferFrom(msg.sender, address(this), amount);
7690
}
7791

7892
// the amount is whatever our current balance is
79-
amount = collateralToken.balanceOf(address(this));
93+
amount = ruCollateralToken.balanceOf(address(this));
8094

8195
RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1);
82-
inputs[0] = makeInput(address(collateralToken), amount);
96+
inputs[0] = makeInput(address(ruCollateralToken), amount);
8397

8498
// The first output pays the collateral token to the shortcut.
8599
// The second output calls the shortcut to supply the collateral.
@@ -94,16 +108,17 @@ contract UseMorpho is SignetStd {
94108
);
95109
}
96110

97-
function repay(address onBehalf, uint256 amount) external {
111+
// Repay some amount of the loan token on behalf of the user.
112+
function repay(address onBehalf, uint256 amount) public {
98113
if (amount > 0) {
99-
loanToken.transferFrom(msg.sender, address(this), amount);
114+
ruLoanToken.transferFrom(msg.sender, address(this), amount);
100115
}
101116

102117
// Send all tokens.
103-
amount = loanToken.balanceOf(address(this));
118+
amount = ruLoanToken.balanceOf(address(this));
104119

105120
RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1);
106-
inputs[0] = makeInput(address(loanToken), amount);
121+
inputs[0] = makeInput(address(ruLoanToken), amount);
107122

108123
// The first output pays the loan token to the shortcut.
109124
// The second output calls the shortcut to repay the loan.
@@ -117,6 +132,31 @@ contract UseMorpho is SignetStd {
117132
outputs
118133
);
119134
}
135+
136+
// Borrow some amount of the loan token and send it to the rollup.
137+
function borrow(address onBehalf, uint256 amount) public {
138+
RollupOrders.Input[] memory inputs = new RollupOrders.Input[](0);
139+
140+
// The first output calls the shortcut to borrow the loan.
141+
// The second output sends the loan token to the user on the rollup.
142+
RollupOrders.Output[] memory outputs = new RollupOrders.Output[](2);
143+
outputs[0] = makeHostOutput(borrowShortcut, amount, onBehalf);
144+
outputs[1] = makeRollupOutput(address(ruLoanToken), amount, msg.sender);
145+
146+
ORDERS.initiate(
147+
block.timestamp, // no deadline
148+
inputs,
149+
outputs
150+
);
151+
}
152+
153+
// Supply collateral and then borrow against it.
154+
function supplyCollateralBorrow(address onBehalf, uint256 supplyAmnt, uint256 borrowAmnt) external {
155+
// Note: this could be more gas efficient by combining into a single
156+
// order.
157+
supplyCollateral(onBehalf, supplyAmnt);
158+
borrow(onBehalf, borrowAmnt);
159+
}
120160
}
121161

122162
abstract contract HostMorphoUser {
@@ -194,3 +234,18 @@ contract HostMorphoSupply is HostMorphoUser {
194234
return true;
195235
}
196236
}
237+
238+
contract HosyMorphoBorrow is HostMorphoUser {
239+
constructor(IMorpho _morpho, MarketParams memory _params) HostMorphoUser(_morpho, _params) {}
240+
241+
// This function
242+
function calculateBorrow() internal pure returns (uint256 tokens) {
243+
return 0;
244+
}
245+
246+
function transferFrom(address filler, address onBehalf, uint256 amount) external returns (bool) {
247+
// borrow some amount of loanToken
248+
morpho.borrow(loadParams(), amount, 0, onBehalf, filler);
249+
return true;
250+
}
251+
}

0 commit comments

Comments
 (0)