Skip to content

Commit 33b5a3e

Browse files
committed
Forte is live
1 parent c733412 commit 33b5a3e

File tree

8 files changed

+105
-154
lines changed

8 files changed

+105
-154
lines changed

docs/blockchain-development-tutorials/forte/fixed-point-128-bit-math.md

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ keywords:
1616
sidebar_label: DeFi Math Utils
1717
---
1818

19-
# High-Precision Fixed-Point 128 Bit Math
19+
# High-Precision Fixed-Point 128 Bit Math
2020

21-
## Overview
22-
Dealing with decimals is a notorious issue for most developers on other chains, especially when working with decentralized finance (DeFi). Blockchains are deterministic systems and floating-point arithmetic is non-deterministic across different compilers and architectures, which is why blockchains use fixed-point arithmetic via integers (scaling numbers by a fixed factor).
21+
Dealing with decimals is a notorious issue for most developers on other chains, especially when working with decentralized finance (DeFi). Blockchains are deterministic systems and floating-point arithmetic is non-deterministic across different compilers and architectures, which is why blockchains use fixed-point arithmetic via integers (scaling numbers by a fixed factor).
2322

2423
The issue with this is that these fixed-point integers tend to be very imprecise when using various mathematical operations on them. The more operations you apply to these numbers, the more imprecise these numbers become. However [`DeFiActionsMathUtils`] provides a standardized library for high-precision mathematical operations in DeFi applications on Flow. The contract extends Cadence's native 8-decimal precision (`UFix64`) to 24 decimals using `UInt128` for intermediate calculations, ensuring accuracy in complex financial computations while maintaining deterministic results across the network.
2524

@@ -54,15 +53,15 @@ let output = afterFee * price // More precision lost
5453
let finalAmount = output / someRatio // Even more precision lost
5554
```
5655

57-
After three-to-four sequential operations, significant cumulative rounding errors can occur, especially when dealing with large amounts. Assuming a rounding error with eight decimals (1.234567885 rounds up to 1.23456789, causing a rounding error of 0.000000005), then after 100 operations with this error and dealing with one million dollars USDF, the protocol loses $0.5 in revenue from this lack of precision. This might not seem like a lot, but if we consider the TVL of Aave, which is around 40 billion USD, then that loss results in $20,000 USD!
56+
After three-to-four sequential operations, significant cumulative rounding errors can occur, especially when dealing with large amounts. Assuming a rounding error with eight decimals (1.234567885 rounds up to 1.23456789, causing a rounding error of 0.000000005), then after 100 operations with this error and dealing with one million dollars USDF, the protocol loses $0.5 in revenue from this lack of precision. This might not seem like a lot, but if we consider the TVL of Aave, which is around 40 billion USD, then that loss results in $20,000 USD!
5857

5958
## The Solution: 24-Decimal Precision
6059

6160
[`DeFiActionsMathUtils`] solves this with `UInt128` to represent fixed-point numbers with 24 decimal places (scaling factor of 10^24). This provides 16 additional decimal places for intermediate calculations, dramatically reducing precision loss.
6261

6362
:::Warning
6463

65-
There is still some precision loss occurring, but it is much smaller than with eight decimals.
64+
There is still some precision loss occurring, but it is much smaller than with eight decimals.
6665

6766
:::
6867

@@ -147,7 +146,7 @@ let protocolFee = DeFiActionsMathUtils.toUFix64RoundUp(calculatedFee)
147146
let displayValue = DeFiActionsMathUtils.toUFix64Round(calculatedValue)
148147
```
149148

150-
**RoundEven** - Select this for scenarios with many repeated calculations where you want to minimize systematic bias. Also known as "[banker's rounding]", this mode rounds ties (exactly 0.5) to the nearest even number, which statistically balances out over many operations, making it ideal for large-scale distributions or statistical calculations.
149+
**RoundEven** - Select this for scenarios with many repeated calculations where you want to minimize systematic bias. Also known as "[banker's rounding]", this mode rounds ties (exactly 0.5) to the nearest even number, which statistically balances out over many operations, making it ideal for large-scale distributions or statistical calculations.
151150

152151
```cadence
153152
// For repeated operations where bias matters
@@ -304,23 +303,23 @@ access(all) fun calculateSwapOutput(
304303
let reserveOut = DeFiActionsMathUtils.toUInt128(outputReserve)
305304
let fee = DeFiActionsMathUtils.toUInt128(feeBasisPoints)
306305
let basisPoints = DeFiActionsMathUtils.toUInt128(10000.0)
307-
306+
308307
// Calculate: inputWithFee = inputAmount * (10000 - fee)
309308
let feeMultiplier = DeFiActionsMathUtils.div(
310309
basisPoints - fee,
311310
basisPoints
312311
)
313312
let inputWithFee = DeFiActionsMathUtils.mul(input, feeMultiplier)
314-
313+
315314
// Calculate: numerator = inputWithFee * outputReserve
316315
let numerator = DeFiActionsMathUtils.mul(inputWithFee, reserveOut)
317-
316+
318317
// Calculate: denominator = inputReserve + inputWithFee
319318
let denominator = reserveIn + inputWithFee
320-
319+
321320
// Calculate output: numerator / denominator
322321
let output = DeFiActionsMathUtils.div(numerator, denominator)
323-
322+
324323
// Return with conservative rounding (round down for user protection)
325324
return DeFiActionsMathUtils.toUFix64RoundDown(output)
326325
}
@@ -345,19 +344,19 @@ access(all) fun calculateCompoundInterest(
345344
let n = DeFiActionsMathUtils.toUInt128(UFix64(periodsPerYear))
346345
let t = DeFiActionsMathUtils.toUInt128(numberOfYears)
347346
let one = DeFiActionsMathUtils.toUInt128(1.0)
348-
347+
349348
// Calculate: rate per period = r / n
350349
let ratePerPeriod = DeFiActionsMathUtils.div(r, n)
351-
350+
352351
// Calculate: (1 + rate per period)
353352
let onePlusRate = one + ratePerPeriod
354-
353+
355354
// Calculate: number of periods = n * t
356355
let totalPeriods = DeFiActionsMathUtils.mul(n, t)
357-
356+
358357
// Note: For production, you'd need to implement a power function
359358
// This is simplified for demonstration
360-
359+
361360
// Calculate final amount with rounding
362361
return DeFiActionsMathUtils.toUFix64Round(finalAmount)
363362
}
@@ -379,11 +378,11 @@ access(all) fun calculateProportionalShare(
379378
let rewards = DeFiActionsMathUtils.toUInt128(totalRewards)
380379
let stake = DeFiActionsMathUtils.toUInt128(userStake)
381380
let total = DeFiActionsMathUtils.toUInt128(totalStaked)
382-
381+
383382
// Calculate: (userStake / totalStaked) * totalRewards
384383
let proportion = DeFiActionsMathUtils.div(stake, total)
385384
let userReward = DeFiActionsMathUtils.mul(proportion, rewards)
386-
385+
387386
// Round down for conservative payout
388387
return DeFiActionsMathUtils.toUFix64RoundDown(userReward)
389388
}
@@ -405,22 +404,22 @@ access(all) fun calculatePriceImpact(
405404
let input = DeFiActionsMathUtils.toUInt128(inputAmount)
406405
let reserveIn = DeFiActionsMathUtils.toUInt128(inputReserve)
407406
let reserveOut = DeFiActionsMathUtils.toUInt128(outputReserve)
408-
407+
409408
// Calculate initial price: outputReserve / inputReserve
410409
let initialPrice = DeFiActionsMathUtils.div(reserveOut, reserveIn)
411-
410+
412411
// Calculate new reserves after trade
413412
let newReserveIn = reserveIn + input
414413
let k = DeFiActionsMathUtils.mul(reserveIn, reserveOut)
415414
let newReserveOut = DeFiActionsMathUtils.div(k, newReserveIn)
416-
415+
417416
// Calculate final price: newOutputReserve / newInputReserve
418417
let finalPrice = DeFiActionsMathUtils.div(newReserveOut, newReserveIn)
419-
418+
420419
// Calculate impact: (initialPrice - finalPrice) / initialPrice
421420
let priceDiff = initialPrice - finalPrice
422421
let impact = DeFiActionsMathUtils.div(priceDiff, initialPrice)
423-
422+
424423
return DeFiActionsMathUtils.toUFix64Round(impact)
425424
}
426425
```
@@ -501,7 +500,7 @@ access(all) fun swap(inputAmount: UFix64) {
501500
inputAmount > 0.0: "Amount must be positive"
502501
inputAmount <= 1000000.0: "Amount exceeds maximum"
503502
}
504-
503+
505504
let inputHP = DeFiActionsMathUtils.toUInt128(inputAmount)
506505
// ... perform calculations
507506
}
@@ -533,4 +532,4 @@ The simple **convert → calculate → convert back** pattern, combined with str
533532
[banker's rounding]: https://learn.microsoft.com/en-us/openspecs/microsoft_general_purpose_programming_languages/ms-vbal/98152b5a-4d86-4acb-b875-66cb1f49433e
534533
[View the DeFiActionsMathUtils source code]: https://github.com/onflow/FlowActions/blob/main/cadence/contracts/utils/DeFiActionsMathUtils.cdc
535534
[Flow DeFi Actions Documentation]: https://developers.flow.com/blockchain-development-tutorials/forte/flow-actions
536-
[Cadence Fixed-Point Numbers]: https://cadence-lang.org/docs/language/values-and-types/fixed-point-nums-ints
535+
[Cadence Fixed-Point Numbers]: https://cadence-lang.org/docs/language/values-and-types/fixed-point-nums-ints

docs/blockchain-development-tutorials/forte/flow-actions/basic-combinations.md

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@ keywords:
1111

1212
# Composing Workflows with Flow Actions
1313

14-
:::warning
15-
16-
We are reviewing and finalizing Flow Actions in [FLIP 339]. The specific implementation may change as a part of this process.
17-
18-
We will update these tutorials, but you may need to refactor your code if the implementation changes.
19-
20-
:::
21-
22-
## Overview
23-
2414
Flow Actions are designed to be **composable**, which means you can chain them together like LEGO blocks to build complex strategies. Each primitive has a standardized interface that works consistently across all protocols and eliminates the need to learn multiple APIs. This composability allows atomic execution of multi-step workflows within single transactions, ensuring either complete success or safe failure. When developers combine these primitives, they create sophisticated decentralized finance (DeFi) strategies like automated yield farming, cross-protocol arbitrage, and portfolio rebalancing. The [5 Flow Actions Primitives] are:
2515

2616
- **Source** → Provides tokens on demand by withdrawing from vaults or claiming rewards. Sources respect minimum balance constraints and return empty vaults gracefully when nothing is available.
@@ -321,7 +311,6 @@ This advanced workflow demonstrates the power of combining VaultSource with Zapp
321311

322312
![vault source zapper](./imgs/vaultsource-zapper.png)
323313

324-
325314
**How it works:**
326315

327316
1. VaultSource withdraws tokens from vault while respecting minimum balance.
@@ -389,7 +378,7 @@ let autoBalancer <- FlowActions.createAutoBalancer(
389378
lowerThreshold: 0.8,
390379
upperThreshold: 1.2,
391380
source: rebalanceSource,
392-
sink: rebalanceSink,
381+
sink: rebalanceSink,
393382
oracle: priceOracle,
394383
uniqueID: nil
395384
)
@@ -419,9 +408,9 @@ This advanced compounding strategy maximizes yield by automatically claiming sta
419408
5. Compound interest effect increases overall position size and future rewards.
420409

421410
```cadence
422-
// Restake rewards workflow
411+
// Restake rewards workflow
423412
let rewardsSource = IncrementFiStakingConnectors.PoolRewardsSource(
424-
poolID: 1,
413+
poolID: 1,
425414
staker: userAddress,
426415
vaultType: Type<@FlowToken.Vault>(),
427416
overflowSinks: {},
@@ -436,13 +425,13 @@ let zapper = IncrementFiPoolLiquidityConnectors.Zapper(
436425
)
437426
438427
let swapSource = SwapConnectors.SwapSource(
439-
swapper: zapper,
440-
source: rewardsSource,
428+
swapper: zapper,
429+
source: rewardsSource,
441430
uniqueID: nil
442431
)
443432
444433
let poolSink = IncrementFiStakingConnectors.PoolSink(
445-
staker: userAddress,
434+
staker: userAddress,
446435
poolID: 1,
447436
uniqueID: nil
448437
)
@@ -459,7 +448,6 @@ poolSink.depositCapacity(from: lpTokens)
459448
- **Set-and-Forget**: Automated compounding without manual intervention required.
460449
- **Optimal Conversion**: Zapper ensures efficient reward token to LP token conversion.
461450

462-
463451
## Safety Best Practices
464452

465453
### Always Check Capacity
@@ -528,7 +516,7 @@ Tests individual connectors in isolation to verify they respect their constraint
528516
// Test individual components
529517
test("VaultSource should maintain minimum balance") {
530518
let source = VaultSource(min: 100.0, withdrawVault: vaultCap, uniqueID: nil)
531-
519+
532520
// Test minimum balance enforcement
533521
let available = source.minimumAvailable()
534522
assert(available >= 100.0, message: "Should maintain minimum balance")
@@ -547,7 +535,7 @@ test("Reward harvesting workflow should complete successfully") {
547535
swapper: swapper,
548536
sink: sink
549537
)
550-
538+
551539
let result = workflow.execute()
552540
assert(result.success, message: "Workflow should complete successfully")
553541
}
@@ -564,14 +552,14 @@ test("Strategy should handle price volatility") {
564552
priceOracle: mockPriceOracle,
565553
swapper: mockSwapper
566554
)
567-
555+
568556
// Simulate price changes
569557
mockPriceOracle.setPrice(1.0)
570558
let result1 = strategy.execute()
571-
559+
572560
mockPriceOracle.setPrice(2.0)
573561
let result2 = strategy.execute()
574-
562+
575563
assert(result1 != result2, message: "Strategy should adapt to price changes")
576564
}
577565
```
@@ -591,5 +579,6 @@ In this tutorial, you learned how to combine Flow Actions primitives to create s
591579
Composability is the core strength of Flow Actions. These examples demonstrate how Flow Actions primitives can be combined to create powerful, automated workflows that integrate multiple protocols seamlessly. The framework's standardized interfaces enable developers to chain operations together like LEGO blocks, focusing on strategy implementation rather than protocol-specific integration details.
592580

593581
<!-- Relative links, will not render on page -->
582+
594583
[FLIP 339]: https://github.com/onflow/flips/pull/339/files
595-
[5 Flow Actions Primitives]: intro-to-flow-actions.md
584+
[5 Flow Actions Primitives]: intro-to-flow-actions.md

0 commit comments

Comments
 (0)