-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.slide
810 lines (600 loc) · 32.4 KB
/
README.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
# Building a Lending Protocol that Powers a Yield-bearing Stablecoin Using Stylus
// HOW TO VIEW THIS PRESENTATION: go get golang.org/x/tools/present
A workshop.
bayge
CTO, Fluidity Labs (Superposition, Fluidity Money)
https://superposition.so
@baygeeth
https://github.com/af-afk/arbiverse-talk
## Disclaimers
1. None of this is financial advice
2. I am not convincing you to use any products
3. This is a purely technical workshop
: I feel the need to include this based on the Thai government's rules
: around this.
## The format of this workshop
1. Quick setup: pulling down repo
2. Overview of Stylus: how does it work? High level overview (10 mins)
3. Overview of lending protocols: how do they work? How do some compare? (10 mins)
4. Overview of stablecoins: very high level stablecoin comparison (5 mins?)
5. Building the lending protocol
: Setup of the repo is pulling down a repo with a QR code I will
: provide.
: Originally I'd planned on giving people a SSH/VNC/this platform a team
: member introed to me but I ran out of time!
: This is the flow and my goals for this workshop:
: 1. Provide people with a lot of time to set up their stuff with a
: architecture review, and history/math lesson. I'm going to ask them to
: set themselves up while I speak basically. I won't bother to make sure
: they're paying attention or anything. This is free time for them to take a
: stab at everything I hope!
: 2. Their goal is to get invariants that I hope will teach them about
: Stylus and Rust completed with a automated test suite. This test suite
: will randomly slam their code. Their goal is to get it working.
: 3. For each invariant they get working, which I will eventually begin to
: review on the screen, they will get a gold star in a box. I will provide
: them with a reference implementation. For the icing on the cake, certain
: functions will need to be implemented by them.
: 4. Hopefully by thy end they understand how to do development in Rust Stylus!
## Quick setup (repo download)
.image qr-repo.svg 400 0
Clone with Git
.link https://github.com/af-afk/talk-arbiverse-13-11-24
: We're going to move this with time capped at 10 minutes.
## Quick setup (installation)
.html quick-setup-installation.html
: Capping this stage at 5 minutes. Hopefully people are energised to
: move fast on this. Make it clear that they'll have time to
: install everything while I'm setting the scene.
## Quick setup (overview of Rust 1)
.code overview-rust-1.rs
: Not going to focus on the ownership/borrowing behaviour so much.
## Quick setup (overview of Rust 2)
.code overview-rust-2.rs
## Quick setup (overview of Rust 3)
.code overview-rust-3.rs
## Overview of Stylus (intro to the EVM)
.image overview-of-stylus-evm.svg
## Overview of Stylus (EVM lifecycle expanded)
1. Node gets from, to, gas limit, and calldata from transaction.
2. Begins executing EVM code at to with the info that's in the transaction.
: This is not exactly true, but I'm going to gloss over that for purposes
: of explaining how MultiVM differs.
## Overview of Stylus (EVM lifecycle expanded)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
contract HelloWorld {
uint256 public counter; // Generates selector 0x61bc221a.
function increment() external { // Generates selector 0xd09de08a.
counter++; // Uses a SLOAD and SSTORE operation.
}
}
Generates bytecode equivalent to (simplified and unoptimised):
0x0 calldataload // Loads calldata to the stack.
0xE0 shr // Shifts calldata to get the selector.
dup0 // Dupe the selector part of the calldata.
0x61bc221a eq COUNTER jumpi // Jump to the counter code.
0xd09de08a eq INCREMENT jumpi // Jump to the increment code.
0x0 0x0 revert // We didn't match a selector! Revert!
COUNTER: // Jump table offset for the counter view.
0x0 0x0 sload // Load the first slot in storage to the stack.
mstore // Store in memory to return.
return // Actually return the current value.
: Introducing some operations that are available to the EVM. Including
: SLOAD, SSTORE, and CALLDATALOAD. Explain how the memory
: operations are semantically linked to the traditional EVM, and that
: it's the equivalent of heap memory. Does not include a lot of stuff.
: Note that this is Huff-like syntax, so literal storing of numbers on
: the stack is done with a push operation that I'm glazing over.
: Touch very lightly on what memory is, referring to it explicitly as
: the scratchpad in the hopes that things make sense.
## Overview of Stylus (EVM lifecycle expanded)
.code overview-of-stylus-evm.huff
## Overview of Stylus (EVM lifecycle expanded)
The storage trie:
.image overview-of-stylus-storage-highlevel.svg
: It's important to touch on that storage is a key * value map, and that
: the key is a 32 bit word. The following is the actual use of this!
.image overview-of-stylus-storage-overview.svg
## Overview of Stylus (EVM lifecycle expanded)
The classic EVM lifeycle:
1. The node takes the to, from, calldata, gas limit from the transaction.
2. The node emulates the EVM.
3. The node persists the outcome of certain operations (including SSTORE).
: Recapping what we briefly touched on in the past few slides. This is
: EVM basics, but it's better to ensure that everyone is following along
: before continuing. It's also important to clarify that logging is not
: included in the above example, as well as anything involving nonces,
: verification that transactions are legit, making sure you have enough
: gas for the transaction.
: I guess that the messaging I'm going for here is that the EVM really is
: about storage slot manipulation.
## Overview of Stylus (MultiVM introduction)
//diff -u O overview-of-stylus-classic.txt overview-of-stylus-multivm.txt > patch
//diff2html -i file --format html -o stdout --su hidden -- patch >overview-of-stylus-multivm-inside.html
// Edit the HTMl to remove the header.
.html overview-of-stylus-multivm.html
: Literally, the Arbitrum node sometimes chooses to emulate compiled
: code that's related to a specific address.
## Overview of Stylus (MultiVM introduction)
Why WASM?
: Why develop with WASM Stylus?
1. Open specification that's constantly evolving.
2. Other programming language and optimisation pipelines produce WASM code.
3. Access a broader ecosystem of thirdparty tools.
: 1. Note that the open specification includes extensions for complex
: operations (single instruction multiple data operations, bulk memory
: operations). It also means less development work from the industry to
: maintain and extend. Note that processors are better with doing lots
: at once due to internal pipelining and parallelism operations. Note
: that there are a plethora of bytecode interpreters that do ahead of
: time compilation to native code. Note that the EVM is not inherently
: suitable for functional programming, due to the lack of tail call
: optimisation. Note that the EVM lacks the static jumps and
: needs to go through a process of enhancing the spec for the EVM to
: include stuff like the EOF. Note that the EVM will never be optimised
: at leveraging the processor to its fullest extent, which imo is more of
: a philosophical discussion as to whether that's important.
: 2. Note that other programming language optimisation pipelines (LLVM)
: benefit from decades of experience with producing optimised bytecode.
: Note that there are more instrumentation tools to profile code. Note
: that business logic fuzzing is possible in the native host with multiple
: backends, so it's faster to do. With the WASM target, you can also leverage
: programming language features including Rust's ownership and borrowing rules.
: 3. With Stylus you can simply bring in thirdparty libraries, including
: cryptography libraries, that might be unavailable to classic Solidity/EVM
: users.
## Overview of lending protocols (how does Compound V2 work?)
: This is what I'm going to use to introduce lending protocols:
Some math
: Compound is one of the oldest lending protocols. 1 and 2 are compared
: equivalently for our conversation since from what I understand V1
: and V2's transition was mostly semantics related to the protocol's
: execution, and the addition of the cToken concept.
: It's seen three iterations, with Compound V1 and V2 simply, and
: algorithmically, setting interest rates based on supply and demand. Assets
: are lent to the pool instead of peer to peer. Assets lent are returned
: a fungible form called cTokens in V2, which are gradually convertible to
: more of the underlying asset based on borrowed amounts. This is a reused
: fundamental principle across the various lending protocols. Borrowers must
: pay an amount of interest that accrues gradually from their collateral,
: with that rate being set by something called the utilisation rate, which
: is the share of tokens being borrowed versus supplied, and a rate being
: negotiated by the DAO. Compound V2 maintains an exchange rate for the
: ctoken for the market that you're in that's almost like an option you
: could exercise. Compound compounds interest accrued between interactions.
.caption Only the borrower volatile math without the curve, no fees
.code overview-of-lending-protocols-compound-v1-1.py 0,/E_/
## Overview of lending protocols (how does Compound V2 work?)
.image overview-of-lending-protocols-compound-v1-diagram.svg
//strict digraph {
// Borrower -> Pool [label="Supplies collateral.\nPays interest rate (I_a)."]
// Pool -> Borrower [label="Supplies assets."]
// Supplier -> Pool [label="Supplies assets.\nPays interest rate from borrower - reserve_a."]
//}
- Borrowers supply collateralisation, and receive assets in exchange from suppliers.
- Interest rate is calculated by the borrowing interest rate, which is calculated by the
utilisation rate.
- Borrowers pay this interest rate.
- Suppliers receive the accumulated interest.
: I'm not going to touch immediately on how liquidation works except
: in passing and verbally, other than explaining that if you don't pay
: interest on your loan, and you go below the amount that's considered
: safe by the protocol with respect to your collateral, then someone will
: call a function that will liquidate you.
## Overview of lending protocols (how does Compound V3 work?)
1. Single asset can be borrowed. Different markets UX.
2. Different interest rate for borrowing and supplying, governed by the DAO.
3. UX improvements.
4. Conversion of assets when liquidated to USDC.
.image logo-compound.png 200 0
: Assets can be comingled so that a single asset can be borrowed, with
: the collateral made up of different tokens. This means that you could
: borrow ETH with assets from other tokens.
: The different interest rate for borrowing and supplying are configured by the
: DAO.
: UX improvements in this context include a whitelisting feature to delegate
: responsibilties associated with your address, like repaying loans.
: I'm not going to explore how this changed since the changes were architectural,
: and the math we showed earlier hasn't changed (afaik?)
## Overview of lending protocols (how does Compound V3 work?)
.image overview-of-lending-protocols-compound.png 500 0
## Overview of lending protocols (how does AAVE work?)
: AAVE is seen as a disrupter when compared to Compound. On top of a
: different pool model of borrowing a single asset, it has some unique
: features including a cross-chain transfer feature called portal, which its
: governance is connected to, a broader range of assets, an isolated pool
: feature (typically for new assets) for borrowing a few USD stablecoins
: alongside a mode called "siloed mode", and "efficiency mode" the option
: to leverage a stable interest rate model, compared to a variable rate. It
: features a "safety module" where stakers stake tokens which are used as
: collateral in shortfall events. The function of the exchange rate system
: is similar with the increase of an exchange rate of assets that can be
: redeemed. The stable interest rate loan is more expensive, but more
: predictable financing. Also the UX of the token that represents pool
: participation is different, with aToken being simply the token that you
: have in the pool.
- Stable and variable rate loans
- Siloed mode
- Efficiency mode
- Safety module
- Utilisation function
- Single asset pool
.image logo-aave.png 50 0
: There is a lot of math here. I understand the mechanics involving the
: stable debt, but I don't think it's so important that we focus on that here.
: The common theme here compared to Compound really is the use of the
: utilisation function, with some different UX mechanics for how information
: is presented externally, as well as the support for different types of
: technologies that can be run on top. AAVE itself is quite complex, and it
: has many features. The main thing from a UX perspective between Compound
: and AAVE is the single asset that can be reused across multiple pools.
## Overview of lending protocols (how does Morpho Blue work?)
: Now that we've touched on the super dominant players, let's look at some exotic
: takes on lending protocols. We're going to quickly burst through these
: until we make it to the end, where we will begin finally implementing
: the lending protocol (and stablecoin).
: Morpho Blue is a departure from the permissioned by a DAO approach to
: assets added. Morpho Blue differs in that the governance prebakes some of
: what they refer to as their Loan-to-Value and Liquidation Loan-To-Value
: ratio, which can be used to permissionlessly create markets. Also instead
: of an insurance fund approach that AAVE has taken, bad debt is taken
: from all lenders.
- Liquidation Incentive Layer
- Permissionless creation of markets
- Collateral is not lent out
- Losses are distributed amongst lenders with bad debt
: I want to make clear that this is probably a gross oversimplification
: of Morpho Blue. I get the feeling there's a lot of innovation happening
: in this concept, especially with how Morpho are posturing themselves
: with AAVE, and how it seems some risk management teams broke off
: here. I know that there is some adaptive rate discovery similar to Ajna
: at play but I haven't done the legwork to know how it works yet.
.image logo-morpho.png 50 0
## Overview of lending protocols (how does Agilerate work?)
: A supply and demand curve is used for lending assets, and an interest
: rate controller is used that adjusts the interest rate depending on
: market conditions using a Recursive Least Squares algorithm.
- Algorithmic interest rate controller
: This is a paper, so there's no implementation of this concep that I've
: seen so far. This might be a challenger product to AAVE someday,
: if the interest rate optimisation is compelling enough.
.image overview-of-lending-protocols-agilerate.png 200 0
## Overview of lending protocols (how does Ajna work?)
: Ajna is different in that it's entirely governance free without
: oracles! Instead people create markets themselves. Ajna is based on
: a AMM model, where a quote token, which is created by lenders, and a
: collateral token, which is created by borrowers, is created. This is a
: way to gauge the debt in the pool's value.
: - Pools contain assets committed to price "buckets".
: - Liquidity Provider Balance NFTs.
: - Threshold Price: loan debt divided by collateral with extra margin
: (4%). The value of the loan equalling the debt.
: - Net interest margin: margin collected on loans stored in reserves.
: - Lowest Utilised Price: lowest collateral price against current
: borrows. Lowest bucket that's been borrowed.
: - Highest Threshold Price: Threshold Price of the least collateralised
: loan.
: - Neutral Price: price of a loan at origin, and used as a liquidation
: price.
- No governance (no managers)
- Create markets instantly. Interest and risk priced with AMM model
- Onus of lending risk is extra on supplier
: Buckets contain quote assets, which are the deposits, any collateral,
: and any liquidity provider balances.
: 1. A user supplies their token for lending at price ranges as what
: they're willing to lend to. The value of the least collateralised loan
: (either the Threshold Price, or the Lowest Utilised Price), is known as
: the Highest Threshold Price. They get back LBP.
: In order to remove the loan, the position must not move below the Highest
: Threshold Price! If they want to do so, they have to manipulate the
: market by calling a liquidation on loans below theirs.
: 2. Assets lent above the Highest Threshold Price earn interest from
: the amounts paid by borrowers. A user goes to borrow from the pool by
: pledging collateral to the pool, and then by borrowing a quote token.
: They can withdraw or add liquidity unless it would leave their loan
: uncollateralised. Interest paid on the borrowing position is paid based
: on the pool utilisation, so the more borrowers, the more returns.
: 3. Borrowers that are undercollateralised compared to the Lowest
: Utilisation Price can be liquidated.
: I think the most interesting thing here is that you're trading
: flexibility, and complexity, for easier access to emerging asset
: lending. You can't pull out your position as a lender and lower the
: value of the collateral for example.
.image logo-ajna.svg 50 0
## Overview of lending protocols (how does Ajna work?)
.image overview-of-lending-protocols-ajna.png 500 0
## Overview of lending protocols (Instadapp Fluid)
: Lending protocol, and broader platform. The emphasis of Fluid is
: on the highest Loan to Value ratio in the market (with 95% for ETH).
: Unfortunately, these guys are using the same naming convention for their
: assets as one of my projects (https:fluidity.money). Fluid is a hub and
: spoke model for leveraging the liquidity that you supply.
- Loan to Value based on liquidations
: I'm putting aside the messaging with efficiencies in the above. Instadapp
: want you to use your liquidity in creative ways, so the focus is on a few
: stablecoin markets. The interesting function here is the liquidation system,
: which is spookily similar to Ajna's value system. The debt to collateral
: ratio is the mechanism used for the liqudiation system. There's a branching
: model here with the debt that I don't fully understand.
.image logo-fluid.svg 150 0
## Overview of lending protocols (how do they all stack up?)
: Understanding the various lending protocols is useful using three systems:
: 1. Complexity versus simplicity, and illiquid positions versus liquid
: positions
:
: 2. Few markets versus many markets, and simple UX versus complex UX
:
: 3. Short-term directed accumulation of knowledge versus long-term
: I need to explain the third metric. Are single entity risk managers better
: than multiple? You would prefer the latter, naturally, as opportunity
: to diversify breeds specialisation for different asset types (as the
: space matures). But it's difficult to growth hack I think. Would we have
: Morpho Blue without AAVE accumulating wisdom in its DAO with a centralised
: model with its risk managers? Naturally, Morpho wouldn't have so much if
: it weren't for the managers looking to maximise their ROI with a model
: that lets them manage their risk directly. But they might not have the
: opportunity to have done so if AAVE had pioneered this model from day
: 1. I see this as the problem for Ajna's adoption, it's really cool,
: but relatively speaking, it's not being adopted as much as Compound
: or AAVE, putting aside the name brand value, as its a complex concept,
: and model. It's a model that needs a manager level being built on top in
: the short term, until the industry matures enough to manage it itself
: as the supply side holistically. Instadapp commercialising multiple
: products under the same hat makes a lot of sense with this view. So I
: look at things as short-term knowledge accumulation versus long-term,
: as naturally, the competitive forces will push people towards specialised
: risk managers.
: Compound and AAVE are the more flexible from a borrower and supplier's
: perspective, at the expense of a lack of flexibility with the assets,
: but to the benefit of complexity, and relative to Compound for AAVE,
: capital efficiency. Positions are fully liquid, with not so much ongoing
: maintenance needed for the position management perspective. You might
: say that Compound and AAVE are very growth hack friendly. You might
: argue that inherently a DAO system is superior, since you could build in
: custom controllers that react algorithmically to changes that simply vote via the
: DAO. Compound and AAVE are the pioneers of this model.
: Instadapp is easier to growthhack imo, despite sharing some similarities
: with Ajna. Price discovery liquidity isn't developed day 1 without seeding
: it with vested expertise in the latter, but it is in Instadapp, with the
: oracle system. The growthhacking element is also interesting in how they
: posture themselves as a self-fulfilling flywheel broadly speaking.
.html overview-of-lending-protocols-how-do-they-stack-up.html
## Overview of stablecoins (the different types)
1. Overcollateralised (backed)
2. Undercollateralised (algorithmic)
: I refer to backed stablecoins like USDC, USDT (in theory) as
: "overcollateralised" assets. This is due to the availability of the
: collateral outstripping the demand/utilisation of the pegged asset.
: "Undercollateralised" stablecoins are pegged assets where the underlying
: asset is optionally lent out, backed by a basket of assets, or pegged
: algorithmically to the value of another asset. These, in my non-mainstream
: nomenclature, should be considered undercollateralised since the market
: value is either less than or equal to the value of the pegged asset at
: any time. This might be due to the ratio of users versus liquidity in practice.
## Overview of stablecoins (how do stablecoins work with lending protocols?)
.image overview-of-stablecoins-lending-protocols.svg 400 0
## Overview of stablecoins (how does LUSD work?)
: So far we've reviewed innovation in the lending market space related
: to the market design for the purposes of our discussion.
1. 0% interest on loans
2. Loans repaid normally
: So the one 0% interest on loans works with a one time fee for redemption
: and borrowing. To get LUSD, you pay a small upfront amount.
: I'd be remiss without touching on Liquity's V2 evolution, the BOLD
: stablecoin. The most notable differences are that this functions with
: multiple types of collateral, and that there's a custom interest rate
: that borrowers can set.
## Overview of stablecoins (how does LUSD work?)
: Imagine a situation where you borrow $200 with a collateral of $190. :
: You supply that much worth of ARB. The system checks the value of what :
: you supplied using an oracle, and it records that. You get back $200 of :
: AUSD. You must now pay an interest of 5%, and you must make sure that
: : your collateral never goes below a value 110% of what you borrowed,
: and you borrowed 105% collateral here. If you can do so, then you get to
: keep your money. If the value of what you have goes below your collateral
: requirement, then it creates a situation where the protocol must field
: some bad debt. Ordinarily, in the Compound/AAVE situation, a fund has
: been created to protect the protocol from this. Morpho socialises the
: debt (if I'm recalling correctly) without said fund, and Ajna I can't
: remember. The classic liquidation logic that we learned about earlier,
: as well as some of the ideas that we have apply. If the value of ARB
: were to rise, then you would collect more for your AUSD, since internally
: the accounting is such that you would make money.
: I guess to simplify this, it's almost like you lend to the protocol, and it gives
: you back a token to spend your debt effectively, and it's almost like you don't
: get anything back!
1. User supplies $200 in collateral, priced by a oracle.
2. User gets back $200 LUSD.
3. User must maintain the debt.
## Building the lending protocol and stablecoin (the goals)
1. Lend Staked ARB
2. Receive AUSD (Arb USD)
3. We don't pay the upfront fee, instead we pay ongoing interest
: Staked ARB USD will be a fun little stablecoin built on a relatively
: simple lending system. AUSD could be a infrastructure token that you
: take advantage of to supply liquidity to 9lives' Infrastructure Markets
: (the simple oracle). It would be a lot better to actually take a one time
: fee, since we want to disincentivise liquidity going to and from the
: token, and we're not doing lending for the purposes of lending, but I
: want to keep things simple for this workshop.
Infrastructure
1. A stablecoin with exposure to ARB means native yield for infra providers
2. Ongoing interest will make the stablecoin productive
: So we can subsidise fee-free infrastructure providers who stake their
: assets without building that into the infrastructure toplevel. In the
: 9lives context, we will have a native oracle that works for something
: called a "URL committee", and a "product committee". These participants
: will stake their AUSD to play the game, and with this system we won't
: have to pay them fees!
: Ongoing interest will keep the stablecoin productive. This isn't
: necessarily a good thing, since idle liquidity earning yield is productive
: in a sense that it could be LP in a pool that needs bootstrapping. But,
: we hope that this mechanism will actually work for us in a good way, since
: this isn't a consumer-facing stablecoin so to speak. With this mechanism,
: someone looking to build a product without any native incentives needing
: staking using ARB don't have to worry about anything! Since the ongoing
: interest fee will mean only the strongest will survive in the system
: for this token, which will punish idlers, but the ARB upside will
: attract users!
## Building the lending protocol and stablecoin (the goals)
1. Staker infra is needed
2. We want exposure to ARB
3. This is not a consumer-facing stablecoin
: Punishing users that aren't productive is good for us since we can
: eliminate people who aren't good at playing the infra game (so to
: speak). This will ensure that people have to be making money if they
: supply themselves to any derivative system. Also a native interest
: payment like this could mean revenue opportunities for platforms that
: use this token. Just recaping these facts in this slide.
.image building-the-lending-protocol-and-stablecoin-goals.svg 400 0
: This is the productive stablecoin!
## Building the lending protocol and stablecoin (the primitives)
1. Same mechanism as Liquity without the upfront fee (except security fee)
2. Compound inspired
## Building the lending protocol and stablecoin (high level)
//strict digraph {
// User -> Factory
// Factory -> Lender [label="Creates Token contract using a proxy"]
// Factory -> ERC20 [label="Deploys the proxy code to the implementation"]
// Lender -> ERC20 [label="Controls the minting and burning of the token"]
// Lender -> "Chainlink price feed" [label="The price oracle for getting value"]
//}
.image building-the-lending-protocol-and-stablecoin-high-level.svg 350 0
: In an ideal universe I'd have time to implement a NFT for this!
## Building the lending protocol and stablecoin (part 1)
: Great, we're finally doing things now! We need to first confirm that
: everyone's development suite is fine.
Build the "hello-world" crate.
cd pkg/hello-world
make build
^ If this exists with status 0, success!
## Building the lending protocol and stablecoin (part 2)
: The first instance of someone doing our main task. The goal is to get
: the test suite passing.
cd pkg/hello-world
Get the "is_pet" function passing:
pub fn is_pet(c: Creature) -> bool {
match c {
Creature::Donkey => true,
Creature::Dog | Creature::Human => false,
}
}
Success:
./tests.sh part-1
## Building the lending protocol and stablecoin (how to test contracts)
: Proptest is an automated way for confirming that code holds up against
: invariants. : We'll be implementing variants in functions that check the
: math and UX that we wrote. Proptest will come up with as many attempts as
: it reasonably can, based on a concept called "shrinking", where a binary
: search over the inputs is undertaken. The test code itself should break
: if the invariant isn't okay.
(This is in pkg/fizzbuzzer)
#[storage]
#[entrypoint]
struct Fizzbuzzer {
pub counter: StorageU256,
}
#[public]
impl Fizzbuzzer {
pub fn ctor(&mut self, c: U256) -> Result<(), Vec<u8>> {
self.counter.set(c);
Ok(())
}
pub fn is_fizzbuzz(&self) -> Result<bool, Vec<u8>> {
let c = self.counter.get();
Ok((c % U256::from(3)).is_zero() && (c % U256::from(5)).is_zero())
}
}
: This is my opportunity as well to introduce the shape for public
: functions. The way these things return is with raw revert data.
: Just so everyone knows, I could construct a actual U256 with byte
: data, but my fear is it's too confusing in front of a live studio audience.
## Building the lending protocol and stablecoin (how to test contracts)
#[cfg(test)]
proptest! {
#[motsu::test]
fn test_contract_fizzbuzzer(num in any::<u128>()) {
let mut c = unsafe {
<Fizzbuzzer as stylus_sdk::storage::StorageType>::new(U256::ZERO, 0)
};
let num = U256::from(num);
c.ctor(num).unwrap();
let is_fizz = num % U256::from(3) == U256::ZERO;
let is_buzz = num % U256::from(5) == U256::ZERO;
assert_eq!(c.is_fizzbuzz().unwrap(), is_fizz && is_buzz);
}
}
: Motsu lets you use a fixture-like UX, but we haven't used this, so we're
: compatible with the OZ macro.
: What the WASM environment depends on are functions being exported that
: let them use some of the EVM features like storage and logging. So what
: motsu does is give you that.
## Building the lending protocol and stablecoin (factory design)
: This pattern in this context is totally nonsensical. But it's my intention
: to show how to do stuff like this so it's important to me that we show
: this off.
// Deploy the ERC20 proxy, and set it's proxy later to point to the Lending impl.
let erc20_addr = unsafe {
RawDeploy::new()
.deploy(&create_proxy_bytecode(erc20_impl), U256::ZERO)
.map_err(Error::DeployFailure)?
};
let lending_addr = unsafe {
RawDeploy::new()
.deploy(&create_proxy_bytecode(lending_impl), U256::ZERO)
.map_err(Error::DeployFailure)?
};
erc20_call::initialise(erc20_addr, lending_addr)?;
lending_call::ctor(lending_addr, erc20_addr)?;
Ok((lending_addr, erc20_addr))
: This is basically a boring factory pattern. I just want to show that this is possible.
// Minimal viable proxy bytecode.
pub const NORMAL_PROXY_BYTECODE_1: [u8; 18] = ...;
pub const NORMAL_PROXY_BYTECODE_2: [u8; 16] = ...;
pub fn create_proxy_bytecode(addr: Address) -> [u8; 54] {
concat_arrays!(...)
}
## Building the lending protocol and stablecoin (the oracle)
pub fn get_latest_price() -> Result<U256, Error> {
let w = unwrap_second_word(
&RawCall::new()
.call(CHAINLINK_FEED_ADDR, &latestRoundDataCall {}.abi_encode())
.map_err(Error::ChainlinkError)?,
)?;
if w.is_negative() {
return Err(Error::ChainlinkNegativeFeed);
}
Ok(w.into_raw())
}
## Building the lending protocol and stablecoin (the reference)
def borrow(self, ticket, cur_time, ausd_amt, token_collateral):
usd_collateral = self.oracle.value_of_asset(token_collateral)
if self.utilisation_rate(ausd_amt, usd_collateral) > self.COLLATERAL_REQ:
raise BadDebt
redemption_amt = token_collateral * (ausd_amt / usd_collateral)
security_deposit = redemption_amt * self.SECURITY_DEPOSIT_RATE
token_collateral -= security_deposit
redemption_amt -= security_deposit
self.token_for_redemptions += redemption_amt
self.security_deposits += security_deposit
self.cash_supply += ausd_amt
self.borrows[ticket] = [Timepoint(cur_time, 0)]
self.collateral[ticket] = token_collateral
self.debt[ticket] = ausd_amt
return ausd_amt
1. Prevent them from going over the collateral rate
2. Begin keeping of information
## Building the lending protocol and stablecoin (part 3)
Get the tests passing for the timepoint code!
## Building the lending protocol and stablecoin (part 4)
Get the tests passing for the borrow math!
## Building the lending protocol and stablecoin (part 5)
Get the tests passing for the liquidate code!
## Building the lending protocol and stablecoin (part 6)
Get the tests passing for the
## Follow my frens
.html follow-my-frens.html
## PS
Superposition mainnet the week of the 18th.