Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: flashloans #105

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"contracts/dao/cwd-core",
"contracts/dao/neutron-chain-manager",
"contracts/dao/neutron-flashloans",
"contracts/dao/proposal/*",
"contracts/dao/pre-propose/*",
"contracts/dao/voting/*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"contract_name": "neutron-chain-manager",
"contract_version": "0.3.0",
"contract_version": "0.4.0",
"idl_version": "1.0.0",
"instantiate": {
"$schema": "http://json-schema.org/draft-07/schema#",
Expand Down Expand Up @@ -1985,6 +1985,18 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"software_upgrade_permission"
],
"properties": {
"software_upgrade_permission": {
"$ref": "#/definitions/SoftwareUpgradePermission"
}
},
"additionalProperties": false
}
]
},
Expand Down Expand Up @@ -2108,6 +2120,21 @@
}
}
},
"SoftwareUpgradePermission": {
"type": "object",
"required": [
"cancel_upgrade",
"upgrade"
],
"properties": {
"cancel_upgrade": {
"type": "boolean"
},
"upgrade": {
"type": "boolean"
}
}
},
"SoftwareUpgradeProposal": {
"description": "Deprecated. SoftwareUpgradeProposal defines the struct for software upgrade proposal.",
"deprecated": true,
Expand Down Expand Up @@ -2698,9 +2725,36 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"software_upgrade_permission"
],
"properties": {
"software_upgrade_permission": {
"$ref": "#/definitions/SoftwareUpgradePermission"
}
},
"additionalProperties": false
}
]
},
"SoftwareUpgradePermission": {
"type": "object",
"required": [
"cancel_upgrade",
"upgrade"
],
"properties": {
"cancel_upgrade": {
"type": "boolean"
},
"upgrade": {
"type": "boolean"
}
}
},
"StrategyMsg": {
"oneOf": [
{
Expand Down
27 changes: 27 additions & 0 deletions contracts/dao/neutron-chain-manager/schema/raw/execute.json
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,18 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"software_upgrade_permission"
],
"properties": {
"software_upgrade_permission": {
"$ref": "#/definitions/SoftwareUpgradePermission"
}
},
"additionalProperties": false
}
]
},
Expand Down Expand Up @@ -2079,6 +2091,21 @@
}
}
},
"SoftwareUpgradePermission": {
"type": "object",
"required": [
"cancel_upgrade",
"upgrade"
],
"properties": {
"cancel_upgrade": {
"type": "boolean"
},
"upgrade": {
"type": "boolean"
}
}
},
"SoftwareUpgradeProposal": {
"description": "Deprecated. SoftwareUpgradeProposal defines the struct for software upgrade proposal.",
"deprecated": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,36 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"software_upgrade_permission"
],
"properties": {
"software_upgrade_permission": {
"$ref": "#/definitions/SoftwareUpgradePermission"
}
},
"additionalProperties": false
}
]
},
"SoftwareUpgradePermission": {
"type": "object",
"required": [
"cancel_upgrade",
"upgrade"
],
"properties": {
"cancel_upgrade": {
"type": "boolean"
},
"upgrade": {
"type": "boolean"
}
}
},
"StrategyMsg": {
"oneOf": [
{
Expand Down
4 changes: 4 additions & 0 deletions contracts/dao/neutron-flashloans/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --example neutron-flashloans_schema"
15 changes: 15 additions & 0 deletions contracts/dao/neutron-flashloans/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Build results
/target

# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327)
.cargo-ok

# Text file backups
**/*.rs.bk

# macOS
.DS_Store

# IDEs
*.iml
.idea
41 changes: 41 additions & 0 deletions contracts/dao/neutron-flashloans/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
authors = ["Andrei Zavgorodnii <andrei.z@hadronlans.org>"]
description = "An implementation of Flashloans for Neutron"
edition = "2021"
name = "neutron-flashloans"
repository = "https://github.com/neutron-org/neutron-dao"
version = "0.3.0"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[dependencies]
cosmwasm-schema = {version = "1.3.0"}
cosmwasm-std = {version = "1.3.0"}
cosmwasm-storage = {version = "1.3.0"}
cw-controllers = "1.1.0"
cw-paginate = {path = "../../../packages/cw-paginate"}
cw-storage-plus = "1.1.0"
cw-utils = {version = "1.0.1"}
cw2 = "1.1.0"
cwd-interface = {path = "../../../packages/cwd-interface"}
cwd-macros = {path = "../../../packages/cwd-macros"}
schemars = "0.8.8"
serde = {version = "1.0.175", default-features = false, features = ["derive"]}
serde_with = {version = "3.7.0", features = ["json"]}
thiserror = {version = "1.0"}
neutron-sdk = "0.8.0"
serde-json-wasm = "1.0.1"
prost = { version = "0.12.3", default-features = false }
prost-types = { version = "0.12.3", default-features = false }
cosmos-sdk-proto = { version = "0.20.0", default-features = false }

[dev-dependencies]
anyhow = "1.0.57"
cw-multi-test = "0.16.5"
66 changes: 66 additions & 0 deletions contracts/dao/neutron-flashloans/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Neutron Flashloans

## Overview

The `neutron-flashloans` contract facilitates providing flash loans to smart contracts operating on the Neutron network.

A flash loan is a type of uncollateralized loan in the cryptocurrency and decentralized finance (DeFi) space. It allows
borrowers to borrow funds without providing any collateral, on the condition that the loan is repaid within the same
transaction. If the borrower fails to repay the loan by the end of the transaction, the entire transaction is
reversed, effectively canceling the loan. Flash loans are typically used for arbitrage, collateral swapping, and
refinancing, taking advantage of price discrepancies or temporary liquidity needs without requiring long-term capital.

## Usage

To get a flash loan, a `RequestLoan` message needs to be sent to the `neutron-flashloans` contract:

```rust
struct RequestLoan {
/// The amount that the borrower contract requests; there should be no
/// duplicate denoms and no zero amounts.
amount: Vec<Coin>,
}
```

The sender needs to be a smart-contract that implements a handler for the `ProcessLoan` message:

```rust
#[cw_serde]
pub enum BorrowerInterface {
ProcessLoan {
/// Specifies the address to which the borrower must return the loan amount AND pay the fees.
return_address: Addr,
/// Specifies the loan amount which the borrower must return to the return_address.
loan_amount: Vec<Coin>,
/// Specifies the fee which the borrower must pay to the return_address.
fee: Vec<Coin>,
}
}
```

Upon receiving the `RequestLoan` message, the `neutron-flashloans` contract will transfer the requested amount to the
borrower and send a `ProcessLoan` message. The borrower can execute any logic within its `ProcessLoan` handler but must
return the `loan_amount` plus the `fee` to the `return_address`. Failure to do so will result in the entire transaction
being reverted.

## Implementation

The `neutron-flashloans` contract does not hold any funds. Instead, it uses `authz` permission from the `source` address
to execute `/cosmos.bank.v1beta1.MsgSend` on its behalf. For Neutron, the `source` address must be set to the Treasury (
DAO core) contract address.

* The `RequestLoan` handler ensures there is no active loan, validates the loan amount (no duplicate or zero coins),
calculates the expected balance (current balance + fee) of the source after repayment, and records the loan details in
storage. If the `source` does not have the requested amount of funds, an error will be returned. Finally, it instructs
the source to send the requested amount to the borrower via `authz`, encapsulated in a `stargate message`. This
message is submitted as a submessage with a `reply_on_success` strategy, meaning if it fails, the transaction is
reverted.
* Upon successful execution of the `/cosmos.bank.v1beta1.MsgSend` message, the `neutron-flashloans` contract sends
a `ProcessLoan` submessage with a `reply_on_success` strategy to the borrower contract.
* After receiving a successful reply to the `ProcessLoan` message, the `neutron-flashloans` contract verifies that the
borrower has returned the funds and paid the fee, then it deletes the loan information.

## Security advice

When writing a borrower contract, ensure that the `ProcessLoan` handler has proper permissions. It should only be
callable when your contract has previously requested a loan and only by the `neutron-flashloans` contract.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cosmwasm_schema::write_api;
use neutron_flashloans::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};

fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
migrate: MigrateMsg
}
}
Loading
Loading