diff --git a/README.md b/README.md index ee498517..90464d45 100644 --- a/README.md +++ b/README.md @@ -169,4 +169,23 @@ yarn build # Publish to npm npm publish --access public +``` + +## 📄 Whitepaper + +To generate a pdf version of the whitepaper, you need to install mdbook: +```sh +cargo install mdbook +# Install mdbook-pdf +cargo install mdbook-pdf + +# Install mdbook-katex +cargo install mdbook-katex +``` + + Then, run the following command: +```sh +cd apps/docs/10-whitepaper +mdbook build + ``` \ No newline at end of file diff --git a/apps/contracts/src/tests/dev.ts b/apps/contracts/src/tests/dev.ts index 9177b236..0667592d 100644 --- a/apps/contracts/src/tests/dev.ts +++ b/apps/contracts/src/tests/dev.ts @@ -1,6 +1,7 @@ + import { airdropAccount } from "../utils/contract.js"; import { withdrawFromVault } from "./vault.js"; -import { Keypair } from "@stellar/stellar-sdk"; +import { Keypair, xdr } from "@stellar/stellar-sdk"; const user = Keypair.fromSecret("SA77N6PLHDFRYDNYE3YJQBPTRNODMVYP5WWF2SG42DXB52GW2FWOG2B3") const contract = "CCNWF3D7FJCZKYCAD6FAO3JNPRHG6SVXHO5YTFDZRXSPOJXL6TIBWP3Y" @@ -10,6 +11,11 @@ const withdrawResult = // await withdrawFromVault(contract, BigInt(10000), user) console.log('🚀 ~ withdrawResult:', withdrawResult); -// const badUser = Keypair.random() -// await airdropAccount(badUser); -// await withdrawFromVault(contract, BigInt(1000), badUser) \ No newline at end of file +const envelopeXdr: xdr.TransactionEnvelope = withdrawResult.result.envelopeXdr.toXDR("base64") +console.log('🚀 ~ env:', envelopeXdr) +const decodedEnvelope = xdr.ScVal.fromXDR(Buffer.from(envelopeXdr.toXDR("base64"), "base64"), "raw") +console.log('🟢',decodedEnvelope) +/* const equisderre = xdr.ScVal.fromXDR(env, "base64") +console.log(equisderre) */ +/* const envelope = xdr.TransactionEnvelope.fromXDR(withdrawResult.result.envelopeXdr, "base64") +console.log('🚀 ~ envelope:', envelope) */ \ No newline at end of file diff --git a/apps/contracts/src/tests/vault.ts b/apps/contracts/src/tests/vault.ts index 2f09f824..ee24c0ac 100644 --- a/apps/contracts/src/tests/vault.ts +++ b/apps/contracts/src/tests/vault.ts @@ -226,7 +226,7 @@ export async function investVault( val: entry.asset.toScVal(), // Convert asset address to ScVal }), new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("strategy_investments"), + key: xdr.ScVal.scvSymbol("strategy_allocations"), val: xdr.ScVal.scvVec( entry.strategy_investments.map((investment) => xdr.ScVal.scvMap([ @@ -235,7 +235,7 @@ export async function investVault( val: nativeToScVal(BigInt(investment.amount), { type: "i128" }), // Ensure i128 conversion }), new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("strategy"), + key: xdr.ScVal.scvSymbol("strategy_address"), val: investment.strategy.toScVal(), // Convert strategy address }), ]) diff --git a/apps/contracts/vault/src/test/vault/withdraw.rs b/apps/contracts/vault/src/test/vault/withdraw.rs index 2e4feb5a..5695350c 100644 --- a/apps/contracts/vault/src/test/vault/withdraw.rs +++ b/apps/contracts/vault/src/test/vault/withdraw.rs @@ -42,7 +42,7 @@ fn negative_amount() { // check that withdraw without balance after initialized returns error InsufficientBalance #[test] -fn total_supply_0() { +fn zero_total_supply() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); let strategy_params_token0 = create_strategy_params_token0(&test); diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore index 683584b6..2ebb8ad5 100644 --- a/apps/docs/.gitignore +++ b/apps/docs/.gitignore @@ -1,2 +1,3 @@ # we want to be able to compile the book locally and not push that to the repo -_book/ \ No newline at end of file +_book/ +book/ \ No newline at end of file diff --git a/apps/docs/01-introduction/README.md b/apps/docs/01-introduction/README.md index 02deee53..c8bcf089 100644 --- a/apps/docs/01-introduction/README.md +++ b/apps/docs/01-introduction/README.md @@ -1,2 +1,5 @@ # Introduction -DeFindex is a protocol where users can define how investment are distributed among multiple DeFi protocols and strategies. \ No newline at end of file +DeFindex is a protocol where users can define how investment are distributed among multiple DeFi protocols and strategies. + +You can find the whitepaper [here](../10-whitepaper/README.md). +and a PDF version [here](https://drive.proton.me/urls/ZGFGQ7JAKC#IzQdqXo8r331). \ No newline at end of file diff --git a/apps/docs/10-whitepaper/02-state-of-the-art/README.md b/apps/docs/10-whitepaper/02-state-of-the-art/README.md deleted file mode 100644 index 7241acaf..00000000 --- a/apps/docs/10-whitepaper/02-state-of-the-art/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# State of the Art -From all types of DeFi protocols that achieve similar goals currently available on different ecosystem, we have selected 3 to define the basic concepts for DeFidex. These are **Yearn.Finance**, **SetsProtocol** and **YieldYak**. \ No newline at end of file diff --git a/apps/docs/10-whitepaper/03-the-defindex-approach/01-design-decisions.md b/apps/docs/10-whitepaper/03-the-defindex-approach/01-design-decisions.md index 112c1e33..3dbc566a 100644 --- a/apps/docs/10-whitepaper/03-the-defindex-approach/01-design-decisions.md +++ b/apps/docs/10-whitepaper/03-the-defindex-approach/01-design-decisions.md @@ -1,25 +1,27 @@ # Design Decisions We have decided to do: -## Multi Assets Index. -We think is important to offer diversified Indexes to our users, not only in the platforms or strategies they will be interacting, but also in the assets they will be exposed to. +## Multi Assets Vaults. +We think is important to offer diversified Vaults to our users, not only in the platforms or strategies they will be interacting, but also in the assets they will be exposed to. ## AMM Liquidity Pool Support When supporting a AMM Liquity Pool, the underlying asset will be considered as the **AMM LP token**, for example, for a Soroswap USDC-XLM liquidity pool, the underlying asset will be the Soroswap-USDC-XLM-LP token and not the USDC or XLM tokens. ## User should provide the exact underlying assets -Even if we would provide the best user experience, every Index will only accept the corresponding assets it will be using for its strategies. We can help the user to get these assets before investing in the Index(See Zapper contract). However it is a decision that the Vault will only accept the desired assets in the correct ratio. +Even if we would provide the best user experience, every Vault only accepts the corresponding assets it will be using for its strategies. We can help the user to get these assets before investing in the Vault(See Zapper contract). However it is a decision that the Vault will only accept the desired assets in the correct ratio. To understand better why we decide this please check the [Why we can`t swap on deposit](../10-apendix/01-why-we-cant-swap-on-deposit-or-withdraw.md) section. ## IDLE funds. -- Security: Enables emergency withdrawal -- Performance: Separate high CPU instructions limits tx. -- Transaction Cost: Enable small investment that wont be affected by costly txs. +IDLE funds are funds that are not being used for any strategy. But they are protected by being held inside the DeFindex Smart Contracts. +- Security: Enables emergency withdrawal. This means that if a DeFi protocol gets too risky, the users won't lose their funds because they can be withdrawn from the DeFi protocol to the DeFindex Smart Contracts. +- Performance: Enable multi transaction movements. +- Transaction Cost: Enable small transactions that wont be affected by costly txs. ## Emergency Withdrawal -- Secutiry. We have roles. +- It allows the Emergency Manager to rescue funds in case of an emergency. These are held in the DeFindex Smart Contracts. Thus, the users won't lose their funds and they will be able to withdraw them anytime. ## Roles -- Manager -- Emergency \ No newline at end of file +- Manager: Can change the Emergency Manager and the Fee Receiver. Rebalance between strategies to optimize the performance and minimize the risk. +- Emergency Manager: Can rescue funds in case of an emergency. +- Fee Receiver: Receives the fees that the protocol pays to incentivize good management. \ No newline at end of file diff --git a/apps/docs/10-whitepaper/03-the-defindex-approach/README.md b/apps/docs/10-whitepaper/03-the-defindex-approach/README.md index f002ebe4..0ac38f62 100644 --- a/apps/docs/10-whitepaper/03-the-defindex-approach/README.md +++ b/apps/docs/10-whitepaper/03-the-defindex-approach/README.md @@ -1 +1,3 @@ -# The DeFindex Approach \ No newline at end of file +# The DeFindex Approach + +In this section we will describe the approach we took to build DeFindex. Why we chose the design decisions we made and how we tried to improve the current state of the art, leveraging the Stellar ecosystem. \ No newline at end of file diff --git a/apps/docs/10-whitepaper/02-state-of-the-art/01-yearn-finance.md b/apps/docs/10-whitepaper/04-state-of-the-art/01-yearn-finance.md similarity index 100% rename from apps/docs/10-whitepaper/02-state-of-the-art/01-yearn-finance.md rename to apps/docs/10-whitepaper/04-state-of-the-art/01-yearn-finance.md diff --git a/apps/docs/10-whitepaper/02-state-of-the-art/02-tokensets.md b/apps/docs/10-whitepaper/04-state-of-the-art/02-set-protocol.md similarity index 100% rename from apps/docs/10-whitepaper/02-state-of-the-art/02-tokensets.md rename to apps/docs/10-whitepaper/04-state-of-the-art/02-set-protocol.md diff --git a/apps/docs/10-whitepaper/04-state-of-the-art/README.md b/apps/docs/10-whitepaper/04-state-of-the-art/README.md new file mode 100644 index 00000000..05cb593c --- /dev/null +++ b/apps/docs/10-whitepaper/04-state-of-the-art/README.md @@ -0,0 +1,5 @@ +# State of the Art +From all types of DeFi protocols that achieve similar goals currently available on different ecosystem, we have selected 2 to define the basic concepts for DeFidex. These are **Yearn.Finance** and **SetProtocol**. + +- [Yearn.Finance](01-yearn-finance.md) +- [SetProtocol](02-set-protocol.md) diff --git a/apps/docs/10-whitepaper/10-appendix/01-why-we-cant-swap-on-deposit-or-withdraw.md b/apps/docs/10-whitepaper/05-appendix/01-why-we-cant-swap-on-deposit-or-withdraw.md similarity index 100% rename from apps/docs/10-whitepaper/10-appendix/01-why-we-cant-swap-on-deposit-or-withdraw.md rename to apps/docs/10-whitepaper/05-appendix/01-why-we-cant-swap-on-deposit-or-withdraw.md diff --git a/apps/docs/10-whitepaper/05-appendix/README.md b/apps/docs/10-whitepaper/05-appendix/README.md new file mode 100644 index 00000000..169b0bed --- /dev/null +++ b/apps/docs/10-whitepaper/05-appendix/README.md @@ -0,0 +1,3 @@ +# Appendix + +- [Why we can't swap on deposit or withdraw](01-why-we-cant-swap-on-deposit-or-withdraw.md) \ No newline at end of file diff --git a/apps/docs/10-whitepaper/10-appendix/README.md b/apps/docs/10-whitepaper/10-appendix/README.md index 606e30e6..044ae324 100644 --- a/apps/docs/10-whitepaper/10-appendix/README.md +++ b/apps/docs/10-whitepaper/10-appendix/README.md @@ -1 +1,3 @@ -# Apendix \ No newline at end of file +# Apendix + +[Why we can't swap on deposit or withdraw](01-why-we-cant-swap-on-deposit-or-withdraw.md) \ No newline at end of file diff --git a/apps/docs/10-whitepaper/README.md b/apps/docs/10-whitepaper/README.md index a0634abe..cd30f668 100644 --- a/apps/docs/10-whitepaper/README.md +++ b/apps/docs/10-whitepaper/README.md @@ -1,6 +1,48 @@ # DeFindex Whitepaper +This protocol by Palta Labs. Francisco Catrileo | Joaquin Soza | Esteban Iglesias -## Abstract -DeFindex is a set of Smart Contracts to Interact better with different Descentralized Finance protocols on the Stellar / Soroban Blockchain +### Introduction +- [Introduction](./01-introduction/README.md) +- [Core Concepts](./01-introduction/02-core-concepts.md) + + +### The DeFindex Approach +- [Overview](./03-the-defindex-approach/README.md) +- [Design Decisions](./03-the-defindex-approach/01-design-decisions.md) + +### Contracts +- [Vault Contract](./03-the-defindex-approach/02-contracts/01-vault-contract.md) +- [Strategy Contract](./03-the-defindex-approach/02-contracts/02-strategy-contract.md) +- [Zapper Contract](./03-the-defindex-approach/02-contracts/02-zapper-contract.md) + +### State of the Art +- [State of the Art](./04-state-of-the-art/README.md) + +### Appendix +- [Appendix](./05-appendix/README.md) + +### Abstract + +DeFindex is a suite of smart contracts designed to facilitate interaction with various Decentralized Finance (DeFi) protocols on the Stellar/Soroban Blockchain. It enables users to create custom strategies, allowing investments to be distributed across multiple DeFi protocols in a streamlined manner. The protocol serves two primary audiences: + +1. **Wallet Users (including Web2 users):** DeFindex provides a simplified interface that wallet developers can integrate into their platforms, enabling users to access DeFi investment services effortlessly. +2. **Expert Users:** For experienced investors, DeFindex offers an efficient way to diversify investments without the complexity of building and managing their own strategies. + +Inspired by projects such as Yearn, Set Protocol, Compound, and YieldYak, DeFindex adapts their core principles to the Stellar ecosystem. + +The protocol comprises three main components: + +1. **Factory:** A smart contract responsible for creating new Vaults. +2. **Vaults:** The primary contracts through which users interact, enabling deposits, withdrawals, and position adjustments. +3. **Strategies:** Contracts that allocate Vault assets across various DeFi protocols. + +To ensure robust functionality and security, DeFindex implements a role-based management system: + +- **Manager:** Oversees strategies and the assets within Vaults. +- **Emergency Manager:** Handles emergency withdrawals. +- **Fee Receiver:** Collects and manages strategy-related fees. + +By combining simplicity for newcomers with advanced features for seasoned users, DeFindex aims to make DeFi more accessible and efficient on the Stellar Blockchain. + diff --git a/apps/docs/10-whitepaper/SUMMARY.md b/apps/docs/10-whitepaper/SUMMARY.md new file mode 100644 index 00000000..12804705 --- /dev/null +++ b/apps/docs/10-whitepaper/SUMMARY.md @@ -0,0 +1,22 @@ +# Summary + +[DeFindex Whitepaper](./README.md) + +# Introduction +- [Introduction](./01-introduction/README.md) +- [Core Concepts](./01-introduction/02-core-concepts.md) + +# The DeFindex Approach +- [Overview](./03-the-defindex-approach/README.md) +- [Design Decisions](./03-the-defindex-approach/01-design-decisions.md) + +# Contracts +- [Vault Contract](./03-the-defindex-approach/02-contracts/01-vault-contract.md) +- [Strategy Contract](./03-the-defindex-approach/02-contracts/02-strategy-contract.md) +- [Zapper Contract](./03-the-defindex-approach/02-contracts/02-zapper-contract.md) + +# State of the Art +- [State of the Art](./04-state-of-the-art/README.md) + +# Appendix +- [Appendix](./05-appendix/README.md) diff --git a/apps/docs/10-whitepaper/book.toml b/apps/docs/10-whitepaper/book.toml new file mode 100644 index 00000000..ac8e3c24 --- /dev/null +++ b/apps/docs/10-whitepaper/book.toml @@ -0,0 +1,20 @@ +[book] +authors = ["Francisco Catrileo", "Joaquin Soza", "Esteban Iglesias"] +language = "en" +multilingual = false +src = "." +title = "DeFindex Whitepaper" + +[output.html] +default-theme = "light" +preferred-dark-theme = "navy" +git-repository-url = "https://github.com/yourusername/yourrepo" +mathjax-support = true + +[preprocessor.katex] +after = ["links"] + +[output.pdf] +optional = true +pdf.links = false +no-links = true \ No newline at end of file diff --git a/apps/docs/11-developer-guides/03-how-to-create-a-strategy.md b/apps/docs/11-developer-guides/03-how-to-create-a-strategy.md new file mode 100644 index 00000000..3edd16d4 --- /dev/null +++ b/apps/docs/11-developer-guides/03-how-to-create-a-strategy.md @@ -0,0 +1,239 @@ +# Implementing a Blend Strategy for DeFindex: A Step-by-Step Guide + +DeFindex is designed for flexibility, enabling developers to create custom strategies that integrate seamlessly with its Vault architecture. In this guide, we’ll explore how to implement a Blend Strategy, which interacts with a Blend Pool to manage assets. The strategy includes key features such as deposits, withdrawals and claiming rewards. + +For more details on the role of strategies in DeFindex, refer to the whitepaper’s strategy section. + +## Overview of the Blend Strategy + +The Blend Strategy handles: + +- Initialization: Sets up the strategy with the Blend Pool address and the underlying asset. +- Deposits: Transfers user assets to the Blend Pool as collateral. +- Withdrawals: Retrieves user assets from the Blend Pool. +- Harvesting: Claims rewards from the Blend Pool for reinvestment or user distribution. +- Balance Tracking: Reports the current holdings of the strategy. + +## Prerequisites + +- Install the defindex-strategy-core crate + +This library provides a standardized interface for DeFindex strategies. + +```bash +cargo add defindex-strategy-core +``` + +- Familiarity with Soroban SDK + +Soroban SDK is used to build and interact with Stellar smart contracts. + +## Understanding Blend Pool Contracts + +Use the Stellar CLI to fetch the Blend Pool WASM: + +```bash +stellar contract fetch --network mainnet --id +``` + +## Implementing the Core Strategy + +Start by defining the BlendStrategy structure and implementing the DeFindexStrategyTrait in lib.rs. + +```rust +use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError}; +use soroban_sdk::{contractimpl, Address, Env, Val, Vec}; + +pub struct BlendStrategy; + +#[contractimpl] +impl DeFindexStrategyTrait for BlendStrategy { + + fn initialize(env: Env, asset: Address, init_args: Vec) -> Result<(), StrategyError> { + // Initialization logic here_ + Ok(()) + } + + fn asset(env: Env) -> Result { + // Return the asset managed by this strategy_ + Ok(Address::random(&env)) + } + + fn deposit(env: Env, amount: i128, from: Address) -> Result<(), StrategyError> { + // Logic to deposit assets into the strategy_ + Ok(()) + } + + fn harvest(env: Env, from: Address) -> Result<(), StrategyError> { + // Reinvest rewards to optimize yields_ + Ok(()) + } + + fn balance(env: Env, from: Address) -> Result { + // Return the current balance_ + Ok(1000) + } + + fn withdraw(env: Env, amount: i128, from: Address) -> Result { + // Withdraw assets from the strategy_ + Ok(amount) + } +} +``` + +This is the basic skeleton. Let’s move on to integrate Blend Pool functionality. + +## Integrating Blend Pool + +Create blend_pool.rs to manage interactions with the Blend Pool smart contract. + +```rust +use soroban_sdk::{vec, Address, Env, Vec}; + +use crate::storage::{get_blend_pool, get_underlying_asset}; + +// Import the Blend Pool WASM_ + +soroban_sdk::contractimport!( + file = "../external_wasms/blend/blend_pool.wasm" +); + +pub type BlendPoolClient<'a> = Client<'a>; + +pub enum RequestType { + SupplyCollateral = 2, + WithdrawCollateral = 3, +} + + +pub fn submit(e: &Env, from: &Address, amount: i128, request_type: RequestType) { + let blend_pool_address = get_blend_pool(e); + let blend_pool_client = BlendPoolClient::new(e, &blend_pool_address); + let underlying_asset = get_underlying_asset(e); + + let requests = vec![&e, Request { + address: underlying_asset, + amount, + request_type: request_type as u32, + }]; + + blend_pool_client.submit(from, from, from, &requests); +} + +pub fn claim(e: &Env, from: &Address) { + let blend_pool_address = get_blend_pool(e); + let blend_pool_client = BlendPoolClient::new(e, &blend_pool_address); + + blend_pool_client.claim(from, &vec![&e, 3u32], from); +} + +pub fn get_positions(e: &Env, from: &Address) -> Positions { + let blend_pool_address = get_blend_pool(e); + let blend_pool_client = BlendPoolClient::new(e, &blend_pool_address); + + blend_pool_client.get_positions(from) +} +``` + +## Managing Strategy Storage + +In storage.rs, maintain initialization flags and asset addresses for the strategy. + +```rust +use soroban_sdk::{contracttype, Address, Env}; + +#[derive(Clone)] +#[contracttype] +pub enum DataKey { + Initialized, + UnderlyingAsset, + BlendPool, +} + +pub fn set_initialized(e: &Env) { + e.storage().instance().set(&DataKey::Initialized, &true); +} + + +pub fn is_initialized(e: &Env) -> bool { + e.storage().instance().has(&DataKey::Initialized) +} + + +pub fn set_underlying_asset(e: &Env, address: &Address) { + e.storage().instance().set(&DataKey::UnderlyingAsset, &address); +} + + +pub fn get_underlying_asset(e: &Env) -> Address { + e.storage().instance().get(&DataKey::UnderlyingAsset).unwrap() +} + + +pub fn set_blend_pool(e: &Env, address: Address) { + e.storage().instance().set(&DataKey::BlendPool, &address); +} + + +pub fn get_blend_pool(e: &Env) -> Address { + e.storage().instance().get(&DataKey::BlendPool).unwrap() +} +``` + +## Updating Core Methods + +Finally, update lib.rs to call the blend_pool methods for deposits, withdrawals, and harvesting. + +```rust +fn initialize( + e: Env, + asset: Address, + init_args: Vec, +) -> Result<(), StrategyError> { + if storage::is_initialized(&e) { + return Err(StrategyError::AlreadyInitialized); + } + + // We get the pool address from init_args that we are passing when initializing the contract + let blend_pool_address = init_args + .get(0) + .ok_or(StrategyError::InvalidArgument)? + .into_val(&e); + + storage::set_initialized(&e); + // Set the blend pool address in the storage + storage::set_blend_pool(&e, blend_pool_address); + // Sets the underlying asset in the strategy, refer to the Whitepaper if confused + storage::set_underlying_asset(&e, &asset); + + // Events come from the strategy core package, so we can have an standarized events for all the defindex strategies + event::emit_initialize(&e, String::from_str(&e, STRATEGY_NAME), asset); + storage::extend_instance_ttl(&e); + Ok(()) +} + +fn deposit(e: Env, amount: i128, from: Address) -> Result<(), StrategyError> { + storage::check_initialized(&e)?; + + blend_pool::submit(&e, &from, amount, RequestType::SupplyCollateral); + Ok(()) +} + + +fn withdraw(e: Env, amount: i128, from: Address) -> Result { + storage::check_initialized(&e)?; + blend_pool::submit(&e, &from, amount, RequestType::WithdrawCollateral); + Ok(amount) +} + + +fn harvest(e: Env, from: Address) -> Result<(), StrategyError> { + storage::check_initialized(&e)?; + blend_pool::claim(&e, &from); + Ok(()) +} +``` + +## Conclusion + +By following this guide, you can create a Blend Strategy for DeFindex that integrates smoothly with Vaults and Blend Pools. The extensible architecture ensures that your strategy remains secure, modular, and aligned with DeFindex’s design principles. Happy coding! 🎉 \ No newline at end of file