diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8423ec78..bfd43361 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -234,6 +234,123 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "piotmag769",
+ "name": "Piotr Magiera",
+ "avatar_url": "https://avatars.githubusercontent.com/u/56825108?v=4",
+ "profile": "https://github.com/piotmag769",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "ftupas",
+ "name": "ftupas",
+ "avatar_url": "https://avatars.githubusercontent.com/u/35031356?v=4",
+ "profile": "https://github.com/ftupas",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "lambda-0x",
+ "name": "lambda-0x",
+ "avatar_url": "https://avatars.githubusercontent.com/u/87354252?v=4",
+ "profile": "https://github.com/lambda-0x",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "Tbelleng",
+ "name": "Tbelleng",
+ "avatar_url": "https://avatars.githubusercontent.com/u/117627242?v=4",
+ "profile": "https://github.com/Tbelleng",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "dic0de",
+ "name": "dic0de",
+ "avatar_url": "https://avatars.githubusercontent.com/u/37063500?v=4",
+ "profile": "https://github.com/dic0de",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "akhercha",
+ "name": "akhercha",
+ "avatar_url": "https://avatars.githubusercontent.com/u/22559023?v=4",
+ "profile": "https://github.com/akhercha",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "VictorONN",
+ "name": "VictorONN",
+ "avatar_url": "https://avatars.githubusercontent.com/u/73134512?v=4",
+ "profile": "https://github.com/VictorONN",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "kasteph",
+ "name": "kasteph",
+ "avatar_url": "https://avatars.githubusercontent.com/u/3408478?v=4",
+ "profile": "https://github.com/kasteph",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "khaeljy",
+ "name": "Khaeljy",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1810456?v=4",
+ "profile": "https://github.com/khaeljy",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "JeanWoked",
+ "name": "JeanWoked",
+ "avatar_url": "https://avatars.githubusercontent.com/u/149107619?v=4",
+ "profile": "https://github.com/JeanWoked",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "vuittont60",
+ "name": "vuittont60",
+ "avatar_url": "https://avatars.githubusercontent.com/u/81072379?v=4",
+ "profile": "https://github.com/vuittont60",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "MavericksFive",
+ "name": "Arnaud Berger",
+ "avatar_url": "https://avatars.githubusercontent.com/u/95299145?v=4",
+ "profile": "https://github.com/MavericksFive",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "faytey",
+ "name": "faytey",
+ "avatar_url": "https://avatars.githubusercontent.com/u/40033608?v=4",
+ "profile": "https://github.com/faytey",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000..a853ae67
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,10 @@
+{
+ "name": "Satoru",
+ "image": "mcr.microsoft.com/devcontainers/base:jammy",
+ "customizations": {
+ "vscode": {
+ "extensions": ["starkware.cairo1"]
+ }
+ },
+ "postCreateCommand": "curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh && curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh -s -- -v 0.8.3"
+}
diff --git a/.example.env b/.example.env
new file mode 100644
index 00000000..1a96da21
--- /dev/null
+++ b/.example.env
@@ -0,0 +1,3 @@
+PROVIDER_URL=
+ACCOUNT_PUBLIC=
+ACCOUNT_PRIVATE=
\ No newline at end of file
diff --git a/.github/semgrep-cairo-rules.yaml b/.github/semgrep-cairo-rules.yaml
new file mode 100644
index 00000000..c06f8bae
--- /dev/null
+++ b/.github/semgrep-cairo-rules.yaml
@@ -0,0 +1,46 @@
+rules:
+- id: unwrap
+ message: Use unwrap() method on $X, use expect() instead
+ languages: [cairo]
+ severity: WARNING
+ pattern: $X.unwrap()
+
+- id: division
+ message: Possible division by zero, use error_utils::check_division_by_zero to report a better error message
+ languages: [cairo]
+ severity: WARNING
+ patterns:
+ - pattern-regex: $Y / $X
+ - pattern-not-regex: error_utils::check_division_by_zero
+
+- id: reentrancy
+ message: |
+ Value mutated after call to external contract
+ severity: ERROR
+ mode: join
+ join:
+ rules:
+ - id: external-contract-declaration
+ languages: [cairo]
+ pattern: |
+ trait $SOME_CONTRACT {}
+ - id: external-call
+ languages: [cairo]
+ pattern: |
+ $SOME_CONTRACT::transfer(...);
+ ...;
+ $X::write(...);
+ on:
+ - 'external-contract-declaration.$SOME_CONTRACT == external-call.$SOME_CONTRACT'
+
+- id: unsafe-arithmetic
+ message: Call unsafe math operators on $X
+ languages: [cairo]
+ severity: ERROR
+ pattern-either:
+ - pattern: $X + $Y
+ - pattern: $X += ...
+ - pattern: $X - $Y
+ - pattern: $X -= ...
+ - pattern: $X * $Y
+ - pattern: $X *= ...
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cdbf30d0..ceffdb56 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,7 +3,7 @@ name: Build
on: [push, pull_request]
env:
- SCARB_VERSION: 0.7.0
+ SCARB_VERSION: 2.3.1
# For the moment we will use nightly versions of scarb to be able to use latest features of Cairo.
# The installation process will be a bit different than when using non nightly versions.
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
- scarb-version: "0.7.0"
+ scarb-version: "2.3.1"
# - name: Set up Scarb
#ses: software-mansion/setup-scarb@v1
# Install Scarb from a nightly release
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index 50d2b9b8..ad517588 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -9,13 +9,13 @@ jobs:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
- scarb-version: "0.7.0"
+ scarb-version: "2.3.1"
- name: Install Semgrep
run: |
- pip install semgrep
+ pip install semgrep==1.45.0
- name: Run Semgrep
- run: semgrep --config https://github.com/avnu-labs/semgrep-cairo-rules/releases/download/v0.0.1/cairo-rules.yaml ./src > semgrep-output.txt
+ run: semgrep --config .github/semgrep-cairo-rules.yaml ./src > semgrep-output.txt
- name: Save Semgrep Output as an Artifact
uses: actions/upload-artifact@v3
with:
@@ -32,19 +32,19 @@ jobs:
~/.cargo
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- - name: Check if Caracal is installed
- id: check-caracal
- run: |
- if ! command -v caracal &> /dev/null; then
- echo "Caracal is not installed. Installing..."
- cargo install --git https://github.com/crytic/caracal --profile release --force
- else
- echo "Caracal is already installed."
- fi
- - name: Run Caracal
- run: caracal detect . > caracal-output.txt
- - name: Save Caracal Output as an Artifact
- uses: actions/upload-artifact@v3
- with:
- name: caracal-cairo
- path: caracal-output.txt
+ # - name: Check if Caracal is installed
+ # id: check-caracal
+ # run: |
+ # if ! command -v caracal &> /dev/null; then
+ # echo "Caracal is not installed. Installing..."
+ # cargo install --git https://github.com/crytic/caracal --profile release --force
+ # else
+ # echo "Caracal is already installed."
+ # fi
+ # - name: Run Caracal
+ # run: caracal detect . > caracal-output.txt
+ # - name: Save Caracal Output as an Artifact
+ # uses: actions/upload-artifact@v3
+ # with:
+ # name: caracal-cairo
+ # path: caracal-output.txt
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 63cb4080..2d601144 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -3,8 +3,7 @@ name: Test
on: [push, pull_request]
env:
- SCARB_VERSION: 0.7.0
- STARKNET_FOUNDRY_VERSION: 0.6.0
+ SCARB_VERSION: 2.3.1
jobs:
check:
@@ -13,7 +12,12 @@ jobs:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
- scarb-version: "0.7.0"
+ scarb-version: ${{ env.SCARB_VERSION }}
+ - uses: foundry-rs/setup-snfoundry@v2
+ with:
+ starknet-foundry-version: 0.10.1
+ - name: Run cairo tests
+ run: snforge test
# - name: Set up Scarb
#ses: software-mansion/setup-scarb@v1
# Install Scarb from a nightly release
@@ -22,7 +26,3 @@ jobs:
# wget https://github.com/software-mansion/scarb-nightlies/releases/download/${NIGHTLY_DATE}/scarb-${NIGHTLY_DATE}-x86_64-unknown-linux-gnu.tar.gz
# tar -xvf scarb-${NIGHTLY_DATE}-x86_64-unknown-linux-gnu.tar.gz
# sudo mv scarb-v${SCARB_VERSION}-x86_64-unknown-linux-gnu/bin/scarb /usr/local/bin
- - name: Install starknet foundry
- run: curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh -s -- -v ${STARKNET_FOUNDRY_VERSION}
- - name: Run cairo tests
- run: snforge
diff --git a/.gitignore b/.gitignore
index f8951466..d0bddf58 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,6 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
-**/.DS_Store
\ No newline at end of file
+**/.DS_Store
+.env
+node_modules
\ No newline at end of file
diff --git a/.tool-versions b/.tool-versions
index ce84f339..697917e5 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1 @@
-scarb 0.7.0
\ No newline at end of file
+scarb 2.3.1
diff --git a/README.md b/README.md
index 1730e492..382d85fe 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,11 @@
+
+
+ [![Exploration_Team](https://img.shields.io/badge/Exploration_Team-29296E.svg?&style=for-the-badge&logo=data:image/svg%2bxml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJhIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxODEgMTgxIj48ZGVmcz48c3R5bGU+LmJ7ZmlsbDojZmZmO308L3N0eWxlPjwvZGVmcz48cGF0aCBjbGFzcz0iYiIgZD0iTTE3Ni43Niw4OC4xOGwtMzYtMzcuNDNjLTEuMzMtMS40OC0zLjQxLTIuMDQtNS4zMS0xLjQybC0xMC42MiwyLjk4LTEyLjk1LDMuNjNoLjc4YzUuMTQtNC41Nyw5LjktOS41NSwxNC4yNS0xNC44OSwxLjY4LTEuNjgsMS44MS0yLjcyLDAtNC4yN0w5Mi40NSwuNzZxLTEuOTQtMS4wNC00LjAxLC4xM2MtMTIuMDQsMTIuNDMtMjMuODMsMjQuNzQtMzYsMzcuNjktMS4yLDEuNDUtMS41LDMuNDQtLjc4LDUuMThsNC4yNywxNi41OGMwLDIuNzIsMS40Miw1LjU3LDIuMDcsOC4yOS00LjczLTUuNjEtOS43NC0xMC45Ny0xNS4wMi0xNi4wNi0xLjY4LTEuODEtMi41OS0xLjgxLTQuNCwwTDQuMzksODguMDVjLTEuNjgsMi4zMy0xLjgxLDIuMzMsMCw0LjUzbDM1Ljg3LDM3LjNjMS4zNiwxLjUzLDMuNSwyLjEsNS40NCwxLjQybDExLjQtMy4xMSwxMi45NS0zLjYzdi45MWMtNS4yOSw0LjE3LTEwLjIyLDguNzYtMTQuNzYsMTMuNzNxLTMuNjMsMi45OC0uNzgsNS4zMWwzMy40MSwzNC44NGMyLjIsMi4yLDIuOTgsMi4yLDUuMTgsMGwzNS40OC0zNy4xN2MxLjU5LTEuMzgsMi4xNi0zLjYsMS40Mi01LjU3LTEuNjgtNi4wOS0zLjI0LTEyLjMtNC43OS0xOC4zOS0uNzQtMi4yNy0xLjIyLTQuNjItMS40Mi02Ljk5LDQuMyw1LjkzLDkuMDcsMTEuNTIsMTQuMjUsMTYuNzEsMS42OCwxLjY4LDIuNzIsMS42OCw0LjQsMGwzNC4zMi0zNS43NHExLjU1LTEuODEsMC00LjAxWm0tNzIuMjYsMTUuMTVjLTMuMTEtLjc4LTYuMDktMS41NS05LjE5LTIuNTktMS43OC0uMzQtMy42MSwuMy00Ljc5LDEuNjhsLTEyLjk1LDEzLjg2Yy0uNzYsLjg1LTEuNDUsMS43Ni0yLjA3LDIuNzJoLS42NWMxLjMtNS4zMSwyLjcyLTEwLjYyLDQuMDEtMTUuOGwxLjY4LTYuNzNjLjg0LTIuMTgsLjE1LTQuNjUtMS42OC02LjA5bC0xMi45NS0xNC4xMmMtLjY0LS40NS0xLjE0LTEuMDgtMS40Mi0xLjgxbDE5LjA0LDUuMTgsMi41OSwuNzhjMi4wNCwuNzYsNC4zMywuMTQsNS43LTEuNTVsMTIuOTUtMTQuMzhzLjc4LTEuMDQsMS42OC0xLjE3Yy0xLjgxLDYuNi0yLjk4LDE0LjEyLTUuNDQsMjAuNDYtMS4wOCwyLjk2LS4wOCw2LjI4LDIuNDYsOC4xNiw0LjI3LDQuMTQsOC4yOSw4LjU1LDEyLjk1LDEyLjk1LDAsMCwxLjMsLjkxLDEuNDIsMi4wN2wtMTMuMzQtMy42M1oiLz48L3N2Zz4=)](https://github.com/keep-starknet-strange)
+
+
@@ -39,6 +44,18 @@ To build the project, run:
scarb build
```
+## Satoru compatible frontends
+
+You can find the list of Satoru-compatible frontends, all of which have been built on top of the Satoru platform :
+
+- [Zohal](https://github.com/Zohal-Starknet/zohal-interface)
+
+## ποΈ Infrastructure
+
+
+
+
+
## π§ͺ Test
To test the project, run:
@@ -49,7 +66,7 @@ snforge
## π Deploy
-To deploy contracts of the saturo, you first need to setup a smart wallet :
+To deploy the contracts of Satoru, you first need to setup a smart wallet :
- Create a signer by following this tutorial : [Signers](https://book.starkli.rs/signers)
@@ -63,6 +80,21 @@ cd scripts
./deploy_contract.sh
```
+## Deployed Contracts
+
+- RoleStore: 0x07eacab18c343f30edfa9336b8eacce9bc56303d43c92609a88e8da25177f5b3
+- DataStore: 0x0549539da18f4d574211365b6abd678ef940444b579900efedcb935210c41481
+- OrderVault: 0x01f1252d6d02feb14cfa88beff415e1524d1cebb31870056567aae257104b6fd
+- Router: 0x00dd0912017ee7c8151555394380acd1012a814916d384b12ca64afa0eae2bc5
+- EventEmitter: 0x0284ae712869c0af4f538e9297e6965d3c9ba9110830944047de8d35da7ea447
+- MarketToken: 0x044391e9498f440cc41ace136ea317f6bfa2080311085d1846529e421974a1d3
+- MarketFactory: 0x05766918626a91ca83f52003eb03bbf1f13174aa22e340c8057d8d5d6affbfcf
+- WithdrawalVault: 0x050c83c2bc74cc50676fdd5598b40f9d0d6d5ccf6ea3478a7999e29473da03f1
+- SwapHandler: 0x039aa67b479f4870878ec6d3002f9fa9b8e98d4d3d10c1f32b5d394a456aab28
+- ReferralStorage: 0x0189463034c24b2cb091dcb515287bea13a4767534f09e52692a4cdc30254001
+- DepositVault: 0x07d435e7ab3a5cd4b872e5725b02898833cb9a7c62e2d9a6a9db324d61e2925e
+
+
## π Resources
Here are some resources to help you get started:
@@ -120,10 +152,27 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Jordy Romuald π» |
- StarkFishinator π» |
+ StarkFishinator π» |
Axel Izsak π» |
Luciefer π» |
tevrat aksoy π» |
+ Piotr Magiera π» |
+ ftupas π» |
+ lambda-0x π» |
+
+
+ Tbelleng π» |
+ dic0de π» |
+ akhercha π» |
+ VictorONN π» |
+ kasteph π» |
+ Khaeljy π» |
+ JeanWoked π» |
+
+
+ vuittont60 π» |
+ Arnaud Berger π» |
+ faytey π» |
@@ -133,4 +182,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
-This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
\ No newline at end of file
diff --git a/Scarb.lock b/Scarb.lock
new file mode 100644
index 00000000..e0bb7f13
--- /dev/null
+++ b/Scarb.lock
@@ -0,0 +1,58 @@
+# Code generated by scarb DO NOT EDIT.
+version = 1
+
+[[package]]
+name = "alexandria_data_structures"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?tag=cairo-v2.3.0-rc0#ae1d5149ff601a7ac5b39edc867d33ebd83d7f4f"
+dependencies = [
+ "alexandria_encoding",
+]
+
+[[package]]
+name = "alexandria_encoding"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?tag=cairo-v2.3.0-rc0#ae1d5149ff601a7ac5b39edc867d33ebd83d7f4f"
+dependencies = [
+ "alexandria_math",
+]
+
+[[package]]
+name = "alexandria_math"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?tag=cairo-v2.3.0-rc0#ae1d5149ff601a7ac5b39edc867d33ebd83d7f4f"
+dependencies = [
+ "alexandria_data_structures",
+]
+
+[[package]]
+name = "alexandria_sorting"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?tag=cairo-v2.3.0-rc0#ae1d5149ff601a7ac5b39edc867d33ebd83d7f4f"
+
+[[package]]
+name = "alexandria_storage"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?tag=cairo-v2.3.0-rc0#ae1d5149ff601a7ac5b39edc867d33ebd83d7f4f"
+
+[[package]]
+name = "pragma_lib"
+version = "1.0.0"
+source = "git+https://github.com/astraly-labs/pragma-lib#fe9a46743254182ac331da488ccfc05e0185cdd0"
+
+[[package]]
+name = "satoru"
+version = "0.1.0"
+dependencies = [
+ "alexandria_data_structures",
+ "alexandria_math",
+ "alexandria_sorting",
+ "alexandria_storage",
+ "pragma_lib",
+ "snforge_std",
+]
+
+[[package]]
+name = "snforge_std"
+version = "0.1.0"
+source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.9.1#da085bd11e1b151d0592f43917136560d9b70d37"
diff --git a/Scarb.toml b/Scarb.toml
index 3c954730..d3b9a28e 100644
--- a/Scarb.toml
+++ b/Scarb.toml
@@ -18,12 +18,13 @@ allowed-libfuncs-list.name = "experimental"
sierra-replace-ids = true
[dependencies]
-starknet = ">=2.1.0"
-alexandria_data_structures = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "a3052ff" }
-alexandria_math = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "a3052ff" }
-alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "a3052ff" }
-alexandria_sorting = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "a3052ff" }
-snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.5.0" }
+starknet = ">=2.3.0"
+alexandria_data_structures = { git = "https://github.com/keep-starknet-strange/alexandria.git", tag = "cairo-v2.3.0-rc0" }
+alexandria_math = { git = "https://github.com/keep-starknet-strange/alexandria.git", tag = "cairo-v2.3.0-rc0" }
+alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git", tag = "cairo-v2.3.0-rc0" }
+alexandria_sorting = { git = "https://github.com/keep-starknet-strange/alexandria.git", tag = "cairo-v2.3.0-rc0" }
+snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.9.1" }
+pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib" }
[tool.snforge]
diff --git a/book/src/README.md b/book/src/README.md
index bb8dfdfe..aed820de 100644
--- a/book/src/README.md
+++ b/book/src/README.md
@@ -4,6 +4,6 @@ Satoru is a cutting-edge synthetics platform for Starknet, taking inspiration fr
![Satoru Whats Up](./assets/satoru-whats-up.gif)
-Like it's namesake, Satoru is **powerful** and **badass**. It's also a bit of a mystery. We don't know what it's capable of yet, but we're excited to find out.
+Like its namesake, Satoru is **powerful** and **badass**. It's also a bit of a mystery. We don't know what it's capable of yet, but we're excited to find out.
-Combine the power of **Starknet** with it's huge computation capacity to the great design of **GMX v2**, and you get Satoru, a synthetics platform that is fast, cheap and scalable.
+Combine the power of **Starknet** with its huge computation capacity with the great design of **GMX v2**, and you get Satoru, a synthetics platform that is fast, cheap and scalable.
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index e528346e..a2645cda 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -9,23 +9,29 @@
- [Smart contracts architecture](smart-contracts-architecture/README.md)
- [Overview](smart-contracts-architecture/overview.md)
- [Adl Module](smart-contracts-architecture/adl-module.md)
+ - [Bank Module](smart-contracts-architecture/bank-module.md)
- [Callback Module](smart-contracts-architecture/callback-module.md)
+ - [Chain Module](smart-contracts-architecture/chain-module.md)
+ - [Config Module](smart-contracts-architecture/config-module.md)
- [Data Module](smart-contracts-architecture/data-module.md)
+ - [Deposit Module](smart-contracts-architecture/deposit-module.md)
- [Exchange Module](smart-contracts-architecture/exchange-module.md)
- [Feature Module](smart-contracts-architecture/feature-module.md)
- [Fee Module](smart-contracts-architecture/fee-module.md)
- [Gas Module](smart-contracts-architecture/gas-module.md)
- - [Liquidation](smart-contracts-architecture/liquidation-module.md)
- - [Mock](smart-contracts-architecture/mock-module.md)
+ - [Liquidation Module](smart-contracts-architecture/liquidation-module.md)
+ - [Market Module](smart-contracts-architecture/market-module.md)
+ - [Mock Module](smart-contracts-architecture/mock-module.md)
- [Nonce Module](smart-contracts-architecture/nonce-module.md)
- [Oracle Module](smart-contracts-architecture/oracle-module.md)
- [Order Module](smart-contracts-architecture/order-module.md)
- [Position Module](smart-contracts-architecture/position-module.md)
+ - [Price Module](smart-contracts-architecture/price-module.md)
- [Pricing Module](smart-contracts-architecture/pricing-module.md)
- [Reader Module](smart-contracts-architecture/reader-module.md)
- [Referral Module](smart-contracts-architecture/referral-module.md)
- - [Router Module](smart-contracts-architecture/router-module.md)
- [Role Module](smart-contracts-architecture/role-module.md)
+ - [Router Module](smart-contracts-architecture/router-module.md)
- [Swap Module](smart-contracts-architecture/swap-module.md)
- [Utils Module](smart-contracts-architecture/utils-module.md)
- [Withdrawal Module](smart-contracts-architecture/withdrawal-module.md)
diff --git a/book/src/assets/satoru-infra.png b/book/src/assets/satoru-infra.png
new file mode 100644
index 00000000..078ffb36
Binary files /dev/null and b/book/src/assets/satoru-infra.png differ
diff --git a/book/src/continuous-integration/README.md b/book/src/continuous-integration/README.md
index 26aaf1aa..0a120922 100644
--- a/book/src/continuous-integration/README.md
+++ b/book/src/continuous-integration/README.md
@@ -4,4 +4,4 @@
A workflow is a configurable automated process that will run one or more jobs. Workflows are defined by a YAML file checked in to your repository and will run when triggered by an event in your repository, or they can be triggered manually, or at a defined schedule.
-In this section we will run through every workflows and give a detailed explanation of their functionalities.
\ No newline at end of file
+In this section we will run through every workflow and give a detailed explanation of their functionalities.
diff --git a/book/src/continuous-integration/workflows.md b/book/src/continuous-integration/workflows.md
index 92e81ce6..77fd8d64 100644
--- a/book/src/continuous-integration/workflows.md
+++ b/book/src/continuous-integration/workflows.md
@@ -175,7 +175,7 @@ The "Test" GitHub Actions workflow (`test.yml`) ensures the code's integrity by
**Environment Variables:**
- **SCARB_VERSION:** Specifies the Scarb version, currently set to `0.7.0`.
-- **STARKNET_FOUNDRY_VERSION:** Defines the version of Starknet Foundry, currently set to `0.5.0`.
+- **STARKNET_FOUNDRY_VERSION:** Defines the version of Starknet Foundry, currently set to `0.8.3`.
**Jobs:**
1. **Test & Check Job**:
@@ -198,18 +198,18 @@ on:
- main
env:
SCARB_VERSION: 0.7.0
- STARKNET_FOUNDRY_VERSION: 0.5.0
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
+ - uses: foundry-rs/setup-snfoundry@v1
+ with:
+ starknet-foundry-version: 0.10.1
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: "0.7.0"
- - name: Install starknet foundry
- run: curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh -s -- -v ${STARKNET_FOUNDRY_VERSION}
- name: Run cairo tests
run: snforge
```
\ No newline at end of file
diff --git a/book/src/getting-started/prerequisites.md b/book/src/getting-started/prerequisites.md
index 8613d429..c569ce3b 100644
--- a/book/src/getting-started/prerequisites.md
+++ b/book/src/getting-started/prerequisites.md
@@ -1,3 +1,14 @@
# Prerequisites
+There are several ways to run Satoru:
+- Install prerequisites on the local system
+- Run in a dev container
+
+## Installation on the local system
+- [Scarb](https://docs.swmansion.com/scarb/download.html)
- [Starknet Foundry](https://foundry-rs.github.io/starknet-foundry/)
+
+## Run in a dev container
+Dev containers provide a dedicated environment for the project. Since the dev container configuration is stored in the `.devcontainer` directory, this ensures that the environment is strictly identical from one developer to the next.
+
+To run inside a dev container, please follow [Dev Containers tutorial](https://code.visualstudio.com/docs/devcontainers/tutorial).
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/adl-module.md b/book/src/smart-contracts-architecture/adl-module.md
index 3755b579..f034442d 100644
--- a/book/src/smart-contracts-architecture/adl-module.md
+++ b/book/src/smart-contracts-architecture/adl-module.md
@@ -1,7 +1,79 @@
-# Adl module
+# Auto-Deleveraging (ADL) Module
-The adl module helps with the auto-deleveraging.
+The ADL Module helps with automatic reduction of leverage in specific markets. This is particularly important for markets where the main token is different from the long token, like a STRK / USD perpetual market where ETH is the long token.
It contains the following Cairo library files:
-- [adl.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/adl/adl.cairo): Helps with the auto-deleveraging. This is particularly for markets with an index token that is different from the long token.
\ No newline at end of file
+- [adl.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/adl/adl_utils.cairo)
+
+## Structures and Types
+
+### `CreateAdlOrderParams`
+
+This struct is utilized within the `create_adl_order` function to encapsulate parameters needed for the order creation, aiding in avoiding stack overflow.
+
+- `data_store`: The `DataStore` contract dispatcher which provides access to a centralized data storage, used for storing and retrieving information about markets, positions, orders, etc.
+- `event_emitter`: The `EventEmitter` contract dispatcher utilized for emitting events on the blockchain, allowing users and other contracts to track changes in the system.
+- `account`: The address of the account whose position is to be reduced. In the ADL context, this typically means closing profitable positions to maintain system solvency.
+- `market`: Address of the concerned market. Each market may have its own parameters and states, and this address helps identify the specific market to be dealt with.
+- `collateral_token`: The address of the token used as collateral for the position. For instance, it's ETH in a STRK/USD market as per the given example.
+- `is_long`: Indicates whether the position is long or short. A long position benefits from a price increase in the market, while a short position benefits from a price decrease.
+- `size_delta_usd`: The size of the position to be reduced, expressed in US Dollars. This specifies how much of the position should be reduced to maintain system solvency.
+- `updated_at_block`: The block number at which the order was updated. This tracks when the ADL order was last created or modified.
+
+## Functions
+
+### `update_adl_state`
+
+Checks the pending profit state and updates an `isAdlEnabled` flag to avoid repeatedly validating whether auto-deleveraging is required. It uses an oracle to fetch market prices and emits an `adl_state_updated` event to notify about the state change. The function also updates the latest ADL block to the current block number to ensure that the ADL status is associated with the most recent data.
+
+### `create_adl_order`
+
+Constructs an ADL order to reduce a profitable position. The function returns a `felt252` type representing the key of the created order, where `felt252` is a type representing a 252-bit field element.
+
+### `validate_adl`
+
+Validates if the requested ADL can be executed by checking the ADL enabled state and ensuring the oracle block numbers are recent enough.
+
+### `get_latest_adl_block`, `set_latest_adl_block`
+
+These functions interact with the `data_store` to retrieve and update the latest ADL block number respectively. `get_latest_adl_block` returns the latest block number at which the ADL flag was updated, and `set_latest_adl_block` sets the latest block number to a new value.
+
+### `get_is_adl_enabled`, `set_adl_enabled`
+
+Interact with the `data_store` to get and set the ADL enabled state for a specified market and position type (long/short).
+
+### `emit_adl_state_updated`
+
+Emits ADL state update events to notify about changes in the ADL state, including the market, position type, PnL to pool factor, max PnL factor, and whether ADL was enabled or disabled.
+
+## Errors
+
+The module defines an `AdlError` to handle ADL-specific errors. Each constant in the `AdlError` module represents a specific error case in the ADL module. Here are the defined errors:
+
+- `ORACLE_BLOCK_NUMBERS_ARE_SMALLER_THAN_REQUIRED`: This error is thrown when the block numbers from the oracle are smaller than required. It ensures that the data being used is recent enough to be reliable.
+
+- `INVALID_SIZE_DELTA_FOR_ADL`: Triggered when the size of the position to be reduced is invalid, for example, if it's larger than the current position size. It ensures that the ADL order size is valid and can be executed.
+
+- `ADL_NOT_ENABLED`: This error occurs if an ADL operation is attempted when ADL is not enabled for the specified market. It serves as a guard to prevent unwanted ADL operations.
+
+- `POSITION_NOT_VALID`: Thrown when a position is not valid, for instance, if it doesn't exist or has already been closed. This error ensures that the position associated with the ADL order is valid and open.
+
+### Others
+- Additional utility modules are imported for array operations, error handling, and callback utilities to support various functionalities within the ADL module.
+
+## Usage Example
+
+```cairo
+// Example of creating an ADL order
+let params = adl_utils::CreateAdlOrderParams {
+ data_store: /* ... */,
+ event_emitter: /* ... */,
+ account: /* ... */,
+ market: /* ... */,
+ collateral_token: /* ... */,
+ is_long: /* ... */,
+ size_delta_usd: /* ... */,
+ updated_at_block: /* ... */,
+};
+adl_utils::create_adl_order(params);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/bank-module.md b/book/src/smart-contracts-architecture/bank-module.md
new file mode 100644
index 00000000..e23de5d8
--- /dev/null
+++ b/book/src/smart-contracts-architecture/bank-module.md
@@ -0,0 +1,83 @@
+# Bank Module (Token Handling)
+
+This module helps to store and move tokens within a contract. It's crucial for a bigger project, letting you do basic bank tasks like starting the contract and sending tokens to a receiver.
+
+It contains the following Cairo library files:
+
+- [bank.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/bank/bank.cairo)
+
+## Structures
+
+### `Storage`
+This struct houses the interface to interact with the `DataStore` contract, which is essential for the storage of data within the contract.
+
+- `data_store`: An instance of `IDataStoreDispatcher` providing the necessary methods to interact with the `DataStore` contract.
+
+## Interface
+
+### `IBank`
+This interface defines the contract's structure and methods. The generic `TContractState` allows for a flexible contract state definition.
+
+- `initialize`: This method sets up the contract with the necessary addresses for the data store and role store contracts.
+- `transfer_out`: A method to facilitate the transfer of tokens from this contract to a specified receiver.
+
+## Implementation
+
+### `Bank` Module
+This module provides the implementation for the `IBank` interface and additional helper methods necessary for the contract's functionality.
+
+#### `constructor`
+This is the constructor method for the contract, which calls the `initialize` method to set up the contract's state.
+
+#### `BankImpl` of `IBank`
+This implementation provides the methods defined in the `IBank` interface.
+
+- `initialize`: Ensures the contract is not already initialized, sets up the role module, and writes the data store address to the contract's state.
+- `transfer_out`: Ensures the caller is a controller before proceeding to call the internal method for token transfer.
+
+#### `BankHelperImpl` of `BankHelperTrait`
+This implementation provides additional helper methods for the contract.
+
+- `transfer_out_internal`: Checks that the receiver is not this contract itself, then performs the token transfer using the `transfer` method from `token_utils`.
+
+## StrictBank Module
+The StrictBank module extends the functionalities of the Bank module by implementing a sync function to update token balances, which can be particularly useful in scenarios of token burns or similar balance changes.
+
+### Interface
+
+#### `IStrictBank`
+This interface extends the `IBank` interface and includes an additional method for syncing token balances.
+
+- `sync_token_balance`: Updates the `token_balances` in case of token burns or similar balance changes. This function returns the new balance of the specified token.
+
+### Implementation
+
+#### `StrictBank` of `IStrictBank`
+This implementation provides the methods defined in the `IStrictBank` interface. It relies on the `Bank` module for `initialize` and `transfer_out` methods, while providing a custom implementation for `sync_token_balance` method which currently returns a placeholder value of `0`.
+
+## Errors
+
+### `BankError`
+This enum encapsulates the error definitions for this contract, ensuring that the contract's methods are used correctly and safely.
+
+- `ALREADY_INITIALIZED`: Thrown if an attempt is made to initialize the contract when it's already initialized. Error code: `'already_initialized'`.
+- `SELF_TRANSFER_NOT_SUPPORTED`: Thrown if an attempt is made to transfer tokens to the contract itself. Error code: `'self_transfer_not_supported'`.
+- `TOKEN_TRANSFER_FAILED`: Thrown if a token transfer operation fails. Error code: `'token_transfer_failed'`.
+
+## Usage Example
+
+Here's a simplified example demonstrating how to initialize and interact with the `Bank` contract in Cairo:
+
+```cairo
+use starknet::{ContractAddress, contract_address_const};
+use satoru::bank::bank::{IBankDispatcherTrait, IBankDispatcher};
+
+// Deploying the Bank contract
+let bank_contract = declare('Bank');
+let constructor_calldata = array![data_store_contract_address.into(), role_store_contract_address.into()];
+let bank_contract_address = bank_contract.deploy(@constructor_calldata).unwrap();
+let bank_dispatcher = IBankDispatcher { contract_address: bank_contract_address };
+
+// Transferring tokens using the Bank contract
+let receiver_address: ContractAddress = 0x202.try_into().unwrap();
+bank_dispatcher.transfer_out(erc20_contract_address, receiver_address, 100_u128);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/callback-module.md b/book/src/smart-contracts-architecture/callback-module.md
index e42b3190..f9d7c368 100644
--- a/book/src/smart-contracts-architecture/callback-module.md
+++ b/book/src/smart-contracts-architecture/callback-module.md
@@ -1,7 +1,157 @@
-# Callback module
+## Callback Module
-Most features of satoru require a two step process to complete. The Callback module is used to facilitate usage of other contracts interacting with Satoru protocol, thus allowing better composability.
+The Callback module is a part of the Satoru project and manages a two-step process. First, a user sends a request, then a keeper sends another transaction to carry out that request. This module makes it easier to work with other contracts by letting a special contract be specified, which gets called after requests are done or cancelled.
-It contains the following smart contracts:
+This module contains the following Cairo library files:
-- [callback_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/callback/callback_utils.cairo): It is handling most functions linked to callback.
\ No newline at end of file
+- [callback](https://github.com/keep-starknet-strange/satoru/tree/main/src/callback)
+
+## Functions
+
+### `validate_callback_gas_limit`
+Validates that the specified `callback_gas_limit` is below a maximum specified value to prevent callback gas limits exceeding the max gas limits per block.
+
+- **Arguments:**
+ - `data_store`: The data store to use.
+ - `callback_gas_limit`: The callback gas limit.
+
+### `set_saved_callback_contract`
+Allows an external entity to associate a callback contract address with a specific account and market.
+
+- **Arguments:**
+ - `data_store`: The `DataStore` contract dispatcher.
+ - `account`: The account to set callback contract for.
+ - `market`: The market to set callback contract for.
+ - `callback_contract`: The callback contract address.
+
+### `get_saved_callback_contract`
+Retrieves a previously stored callback contract address associated with a given account and market from the data store.
+
+- **Arguments:**
+ - `data_store`: The `DataStore` contract dispatcher.
+ - `account`: The account to get callback contract for.
+ - `market`: The market to get callback contract for.
+
+### function_after_deposit_execution, function_after_deposit_cancellation, function_after_withdrawal_execution, function_after_withdrawal_cancellation, function_after_order_execution, function_after_order_cancellation, and function_after_order_frozen
+These functions are callback handlers called after specific actions such as deposit execution, deposit cancellation, withdrawal execution, withdrawal cancellation, order execution, order cancellation, and order frozen respectively.
+
+These functions are callback handlers called after specific actions such as deposit execution, deposit cancellation, withdrawal execution, withdrawal cancellation, order execution, order cancellation, and order frozen respectively.
+
+- **Common Arguments:**
+ - `key`: The key of the order/deposit/withdrawal.
+ - `order`/`deposit`/`withdrawal`: The order/deposit/withdrawal that was executed/cancelled/frozen.
+ - `event_data`: The event log data.
+ - `event_emitter`: The event emitter dispatcher.
+
+### `is_valid_callback_contract`
+Validates that the given address is a contract.
+
+- **Arguments:**
+ - `callback_contract`: The callback contract.
+
+## Errors
+
+### `CallbackError`
+This enum encapsulates the error definitions for this module, ensuring that the contract's methods are used correctly and safely.
+
+- `MAX_CALLBACK_GAS_LIMIT_EXCEEDED`: Thrown when the `callback_gas_limit` exceeds the maximum specified value. Error code: `'max_callback_gas_limit_exceeded'`.
+
+## Interface for `DepositCallbackReceiver`
+
+The `DepositCallbackReceiver` interface defines the callback handlers that are triggered after a deposit operation such as execution or cancellation. This interface is crucial for the callback mechanism within the Satoru project, allowing for additional logic to be executed after a deposit operation.
+
+### `IDepositCallbackReceiver`
+
+This interface specifies the methods for handling callbacks after deposit operations.
+
+#### `after_deposit_execution`
+
+Called after a deposit execution.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the deposit.
+ - `deposit`: The deposit that was executed.
+ - `event_data`: The event log data.
+
+#### `after_deposit_cancellation`
+
+Called after a deposit cancellation.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the deposit.
+ - `deposit`: The deposit that was cancelled.
+ - `event_data`: The event log data.
+
+## Interface for `OrderCallbackReceiver`
+
+The `OrderCallbackReceiver` interface defines the callback handlers that are triggered after an order operation such as execution, cancellation, or being frozen. This interface is vital for the callback mechanism within the Satoru project, allowing for additional logic to be executed after an order operation.
+
+### `IOrderCallbackReceiver`
+This interface specifies the methods for handling callbacks after order operations.
+
+#### `after_order_execution`
+Called after an order execution.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the order.
+ - `order`: The order that was executed.
+ - `event_data`: The event log data.
+
+#### `after_order_cancellation`
+Called after an order cancellation.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the order.
+ - `order`: The order that was cancelled.
+ - `event_data`: The event log data.
+
+#### `after_order_frozen`
+Called after an order is frozen.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the order.
+ - `order`: The order that was frozen.
+ - `event_data`: The event log data.
+
+## Interface for `WithdrawalCallbackReceiver`
+
+The `WithdrawalCallbackReceiver` interface defines the callback handlers that are triggered after a withdrawal operation such as execution or cancellation. This interface is crucial for the callback mechanism within the Satoru project, allowing for additional logic to be executed after a withdrawal operation.
+
+### `IWithdrawalCallbackReceiver`
+This interface specifies the methods for handling callbacks after withdrawal operations.
+
+#### `after_withdrawal_execution`
+Called after a withdrawal execution.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the withdrawal.
+ - `withdrawal`: The withdrawal that was executed.
+ - `event_data`: The event log data.
+
+#### `after_withdrawal_cancellation`
+Called after a withdrawal cancellation.
+
+- **Arguments:**
+ - `self`: The contract state.
+ - `key`: The key of the withdrawal.
+ - `withdrawal`: The withdrawal that was cancelled.
+ - `event_data`: The event log data.
+
+## Usage Example
+
+```cairo
+use starknet::ContractAddress;
+use satoru::callback::callback;
+use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
+
+// Assuming data_store, account, market, and callback_contract are already initialized
+callback::set_saved_callback_contract(data_store, account, market, callback_contract);
+
+// Retrieving the saved callback contract
+let saved_callback_contract = callback::get_saved_callback_contract(data_store, account, market);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/chain-module.md b/book/src/smart-contracts-architecture/chain-module.md
new file mode 100644
index 00000000..3c448ae4
--- /dev/null
+++ b/book/src/smart-contracts-architecture/chain-module.md
@@ -0,0 +1,55 @@
+## Chain Module
+
+The Chain module provides functionalities to query chain-specific variables. It is designed as a library contract for retrieving the current block number and timestamp.
+
+This module contains the following Cairo library file:
+
+- [chain.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/chain/chain.cairo)
+
+## Functions
+
+### `get_block_number`
+Returns the current block number on the Starknet network.
+
+- **Arguments:** None.
+
+- **Returns:** `u64` - The current block number.
+
+### `get_block_timestamp`
+Returns the timestamp of the current block on the Starknet network.
+
+- **Arguments:** None.
+
+- **Returns:** `u64` - The timestamp of the current block.
+
+## Errors
+
+This module does not define any custom errors.
+
+## Interface for `Chain`
+
+The `Chain` interface defines the methods to query chain-specific variables like block number and block timestamp. These methods are crucial for contracts that need to interact with or check chain data.
+
+### `IChain`
+This interface specifies the methods for querying chain-specific variables.
+
+#### `get_block_number`
+Called to retrieve the current block number.
+
+- **Arguments:**
+ - `self`: The contract state.
+
+- **Returns:** `u64` - The current block number.
+
+#### `get_block_timestamp`
+Called to retrieve the timestamp of the current block.
+
+- **Arguments:**
+ - `self`: The contract state.
+
+- **Returns:** `u64` - The timestamp of the current block.
+
+## Usage Example
+
+```cairo
+TODO
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/config-module.md b/book/src/smart-contracts-architecture/config-module.md
new file mode 100644
index 00000000..f2a4b225
--- /dev/null
+++ b/book/src/smart-contracts-architecture/config-module.md
@@ -0,0 +1,63 @@
+# Config Module
+
+The Configuration Module is really important because it lets you manage different settings in the project. You can change and view configurations related to contracts, roles, gas limits, markets, and more. It makes sure everything works within set rules and is crucial for the system to operate properly.
+
+Below is a detailed documentation of the Configuration Module, explaining its structures, types, functions, errors, imports, and a sample usage.
+
+It contains the following Cairo library files:
+
+- [adl.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/config/config.cairo)
+
+## Additional Module: Timelock
+
+Within the system, there's a module named `Timelock` designed to handle functionalities related to time-lock mechanisms. This is crucial for operations that require a predefined time delay for execution, enhancing the security and control over critical operations.
+
+## Structures and Types
+
+### `Storage`
+
+This struct encapsulates the storage fields necessary for the Configuration module, providing interfaces to interact with other contracts and a map to manage allowed base keys.
+
+- `role_store`: An interface to interact with the `RoleStore` contract.
+- `data_store`: An interface to interact with the `DataStore` contract.
+- `event_emitter`: An interface to interact with the `EventEmitter` contract.
+- `allowed_base_keys`: A map to manage the allowed base keys for setting configurations.
+
+## Functions
+
+### `constructor`
+
+This function initializes the `Storage` struct with provided contract addresses and calls `init_allowed_base_keys` function to initialize allowed base keys.
+
+### `set_bool`, `set_address`, `set_felt252`
+
+These functions are implementations of the `IConfig` interface, allowing setting configurations of different data types. They ensure the caller has the `CONFIG_KEEPER` role, validate the base key, compute the full key from the base key and additional data, and set the value in the `DataStore`.
+
+### `init_allowed_base_keys`
+
+This function initializes the map of allowed base keys for setting configurations. It writes true to each base key that is allowed to be set.
+
+### `validate_key`
+
+This function checks that a provided base key is in the list of allowed base keys, throwing `ConfigError::INVALID_BASE_KEY` if it's not.
+
+### `get_full_key`
+
+This function computes the full key from the provided base key and additional data. If there's no additional data, it returns the base key. Otherwise, it computes a Poseidon hash of the concatenated base key and data.
+
+## Errors
+
+### `ConfigError`
+
+This module defines a `ConfigError` to handle configuration-specific errors. Here are the defined errors:
+
+- `INVALID_BASE_KEY`: This error is thrown when a base key provided is not in the list of allowed base keys. It is represented by the constant `'invalid_base_key'` in the `ConfigError` module.
+
+## Usage Example
+
+```cairo
+// Example of setting a bool configuration
+let base_key = /* ... */;
+let data = array![];
+let value = true;
+Config::set_bool(contract_state, base_key, data, value);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/data-module.md b/book/src/smart-contracts-architecture/data-module.md
index 209dddfd..5346f1e1 100644
--- a/book/src/smart-contracts-architecture/data-module.md
+++ b/book/src/smart-contracts-architecture/data-module.md
@@ -1,11 +1,31 @@
-# Data module
+## Data Module
-The data module is reponsible for storing and managing the data of the protocol.
+The Data Module serves as the backbone for storing and managing the protocol's data. Below is a detailed outline of its constituents and their respective functions and responsibilities.
-It contains the following smart contracts:
+### Smart Contracts
-- [DataStore](https://github.com/keep-starknet-strange/satoru/blob/main/src/data/data_store.cairo): The main smart contract of the module. It is responsible for storing the data of the protocol.
+#### [data_store.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/data/data_store.cairo)
+The `DataStore` is the central smart contract of the module, holding the responsibility of maintaining the protocol's data. It manages different entities, including orders, positions, withdrawals, and deposits.
-It contains the following Cairo library files:
+##### Key Features & Responsibilities:
+- **Order Management:** Enables the creation, reading, updating, and deletion of orders, each linked to a specific user account. Orders can be retrieved using their unique keys or can be listed per user account.
+
+- **Position Management:** Manages financial positions associated with user accounts, offering functionalities to manipulate and view positions individually or by user account.
+
+- **Withdrawal Management:** Supports the creation, reading, updating, and deletion of withdrawal requests, and enables the listing of withdrawals by user account.
+
+- **Deposit Management:** Manages user deposits, allowing the creation, reading, updating, and deletion of deposits, viewable individually or listed by user account.
-- [keys.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/data/keys.cairo): Contains functions to generate the keys (entries in the data store) of the protocol.
+- **Market Management:** Facilitates the addition, deletion, and retrieval of markets, managing market indexes and ensuring that only authorized users can perform these operations.
+
+- **Oracle Functions:** Allows setting and getting token IDs, with stringent access controls, ensuring only authorized entities can access them.
+
+- **Access Control and Security:** Implements rigorous access control mechanisms, ensuring that only authorized addresses can perform certain operations. Specific role controls are applied, allowing only addresses with the `CONTROLLER` role to perform sensitive modifications to the contractβs state.
+
+##### Constructor
+The constructor initializes the contract with a `role_store` address, establishing the access control and role management mechanism from the deployment of the contract.
+
+### Cairo Library Files
+
+#### [keys.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/data/keys.cairo)
+This Cairo library file plays a crucial role in generating the keys for the protocol's entries in the data store. The keys serve as unique identifiers, enabling the protocol to accurately access and manage the stored data.
diff --git a/book/src/smart-contracts-architecture/deposit-module.md b/book/src/smart-contracts-architecture/deposit-module.md
index 206a6a5f..1da6bbd0 100644
--- a/book/src/smart-contracts-architecture/deposit-module.md
+++ b/book/src/smart-contracts-architecture/deposit-module.md
@@ -1,9 +1,91 @@
-# Deposit module
+# Deposit Module
-The deposit module contains main satoru functions for deposit, to manage the depositing of liquidity into a market.
+The deposit module contains main Satoru functions for deposit, to manage the depositing of liquidity into a market.
It contains the following Cairo library files:
- [deposit_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/deposit/deposit_utils.cairo): Library for deposit functions, to help with the depositing of liquidity into a market in return for market tokens.
- [deposit.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/deposit/deposit.cairo): Contains Deposit struct.
- [execute_deposit_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/deposit/execute_deposit_utils.cairo): Library for deposit functions, to help with the depositing of liquidity into a market in return for market tokens.
+
+## Structures and Types
+
+### `CreateDepositParams`
+
+This struct is utilized within the `create_deposit` function to encapsulate parameters needed for the deposit creation.
+
+- `receiver`: The address to send the market tokens to.
+- `callback_contract`: The callback contract linked to this deposit.
+- `ui_fee_receiver`: The UI fee receiver.
+- `market`: The market to deposit into.
+- `initial_long_token`: The initial long token address.
+- `initial_short_token`: The initial short token address.
+- `long_token_swap_path`: The swap path into markets for the long token.
+- `short_token_swap_path`: The swap path into markets for the short token.
+- `min_market_tokens`: The minimum acceptable number of liquidity tokens.
+- `execution_fee`: The execution fee for keepers.
+- `callback_gas_limit`: The gas limit for the `callback_contract`.
+
+### `Deposit`
+
+A structure to represent a deposit in the system, containing information such as the addresses of the tokens, amounts deposited, and parameters of the concerned market.
+
+### `DepositError`
+
+Module for deposit-specific error operations.
+
+- `DEPOSIT_NOT_FOUND`: Deposit not found.
+- `DEPOSIT_INDEX_NOT_FOUND`: Deposit index not found.
+- `CANT_BE_ZERO`: Can't be zero.
+- `EMPTY_DEPOSIT_AMOUNTS`: Empty deposit amounts.
+- `EMPTY_DEPOSIT`: Empty deposit.
+
+## Functions
+
+### `create_deposit`
+
+Creates a deposit with the specified parameters, recording the transfer of initial tokens and validating the swap paths.
+
+### `cancel_deposit`
+
+Cancels a deposit, funds are sent back to the user.
+
+### `execute_deposit`
+
+Executes a deposit according to the provided parameters. (Function to be developed)
+
+### `swap`
+
+Performs a token swap according to the provided parameters. (Function to be developed)
+
+## Contracts
+
+### `DepositVault`
+
+The `DepositVault` contract provides functions to initialize the contract, transfer tokens out of the contract, and record a token transfer into the contract.
+
+## Usage Example
+
+```cairo
+// Example of creating a deposit
+let params = CreateDepositParams {
+ receiver: /* ... */,
+ callback_contract: /* ... */,
+ ui_fee_receiver: /* ... */,
+ market: /* ... */,
+ initial_long_token: /* ... */,
+ initial_short_token: /* ... */,
+ long_token_swap_path: /* ... */,
+ short_token_swap_path: /* ... */,
+ min_market_tokens: /* ... */,
+ execution_fee: /* ... */,
+ callback_gas_limit: /* ... */,
+};
+
+let key = create_deposit(
+ data_store,
+ event_emitter,
+ deposit_vault,
+ account,
+ params
+);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/exchange-module.md b/book/src/smart-contracts-architecture/exchange-module.md
index 894ca114..5c40a4ff 100644
--- a/book/src/smart-contracts-architecture/exchange-module.md
+++ b/book/src/smart-contracts-architecture/exchange-module.md
@@ -1,17 +1,21 @@
-# Exchange module
+# Exchange Module
-The exchange module contains main satoru handlers to create and execute actions.
+The Exchange module contains the core functionalities of the Satoru protocol, handling the creation, execution, and cancellation of various actions.
-It contains the following smart contracts:
+## Smart Contracts
-- [AdlHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/adl_handler.cairo): Contract to handle adl.
-- [BaseOrderHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/base_order_handler.cairo): Base contract for shared order handler functions.
-- [DepositHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/deposit_handler.cairo): Contract to handle creation, execution and cancellation of deposits.
-- [LiquidationHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/liquidation_handler.cairo): Contract to handle liquidation.
-- [OrderHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/order_handler.cairo): Contract to handle creation, execution and cancellation of orders.
-- [WithdrawalHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/withdrawal_handler.cairo): Contract to handle creation, execution and cancellation of withdrawals.
+The module comprises the following smart contracts:
-It contains the following Cairo library files:
+- [AdlHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/adl_handler.cairo): This contract manages the ADL (Automatic Deleveraging) process.
+- [BaseOrderHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/base_order_handler.cairo): A base contract encapsulating shared functionalities for order handling.
+- [DepositHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/deposit_handler.cairo): Manages the creation, execution, and cancellation of deposit requests.
+- [LiquidationHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/liquidation_handler.cairo): Handles the liquidation process.
+- [OrderHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/order_handler.cairo): Manages the creation, execution, and cancellation of orders.
+- [WithdrawalHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/withdrawal_handler.cairo): Handles the creation, execution, and cancellation of withdrawal requests.
-- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/error.cairo): Contains the error codes of the module.
-- [exchange_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/withdrawal_event_utils.cairo): Contains request validation utility function.
+## Libraries
+
+The module also includes the following library files for utility and error handling:
+
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/error.cairo): Contains the module's error codes encapsulated as `ExchangeError`.
+- [exchange_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/exchange/withdrawal_event_utils.cairo): Provides request validation utility functions.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/feature-module.md b/book/src/smart-contracts-architecture/feature-module.md
index 342cecb6..e45bab08 100644
--- a/book/src/smart-contracts-architecture/feature-module.md
+++ b/book/src/smart-contracts-architecture/feature-module.md
@@ -1,7 +1,41 @@
-# Feature module
+# Feature Module
-The Feature is used to validate if a feature is enabled or disabled.
+The Feature Module checks if different parts of the system are turned on or off. Itβs really important for keeping the system stable and working correctly.
-It contains the following smart contracts:
+It encompasses the following smart contracts:
+- [feature_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/feature/feature_utils.cairo): Central to the module, this contract is responsible for validating the operational status of a feature, determining whether it is enabled or disabled.
-- [feature_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/feature/feature_utils.cairo): It is responsible for validating if a feature is enabled or disabled.
+## β οΈ Warning
+Disabling a feature should be performed with extreme caution and only in absolutely necessary situations, as it can lead to unexpected and potentially harmful effects, such as operational discrepancies and system instability.
+
+## Functions
+
+### `is_feature_disabled`
+
+```cairo
+fn is_feature_disabled(data_store: IDataStoreDispatcher, key: felt252) -> bool
+```
+
+- **Objective:** Determines the operational status of a specified feature.
+- **Parameters:**
+ - `data_store`: The data storage contract dispatcher, facilitating interaction with stored data.
+ - `key`: The feature key representing the specific feature in question.
+- **Returns:** A boolean indicating whether the feature is disabled.
+
+### `validate_feature`
+
+```cairo
+fn validate_feature(data_store: IDataStoreDispatcher, key: felt252)
+```
+
+- **Objective:** Validates the operational status of a specified feature and reverts the operation if the feature is disabled.
+- **Parameters:**
+ - `data_store`: The data storage contract dispatcher.
+ - `key`: The feature key representing the specific feature in question.
+- **Implications:** Essential for maintaining system integrity by halting operations related to disabled features.
+
+## Errors
+
+### `FeatureError`
+
+- **DISABLED_FEATURE:** This error is triggered when an attempt is made to operate a disabled feature, indicating a breach in feature utilization protocols.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/fee-module.md b/book/src/smart-contracts-architecture/fee-module.md
index 722f896d..c23582e0 100644
--- a/book/src/smart-contracts-architecture/fee-module.md
+++ b/book/src/smart-contracts-architecture/fee-module.md
@@ -1,13 +1,31 @@
-# Fee module
+# Fee Module
-The fee module is for the fees actions.
+The Fee Module takes care of everything related to fees. Itβs crucial for moving and claiming fees in specific markets.
-It contains the following smart contracts:
+The module incorporates the following components:
+- [FeeHandler.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/fee_handler.cairo): The nucleus of the module, entrusted with initializing the contract and claiming fees from identified markets.
+- [fee_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/fee_utils.cairo): A collection of utility functions vital for orchestrating fee actions and interactions such as claiming and incrementing fees.
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/error.cairo): A repository of error codes and messages related to fee operations, essential for accurate error handling and resolution.
-- [FeeHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/fee_handler.cairo): The main smart contract of the module. It is responsible for claiming the fees from the specified markets.
+## Structures and Types
-It contains the following Cairo library files:
+### `FeeHandler`
-- [fee_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/error.cairo): Fee actions
+The `FeeHandler` struct is pivotal within the module, managing the interactions and executions of fee-related functions, ensuring the integrity of fee transfers and claims.
-- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/fee/error.cairo): Contains the error codes of the module.
+- `data_store`: The `DataStore` contract dispatcher, a centralized repository for data storage, crucial for retrieving and storing information related to markets, positions, orders, etc.
+- `role_store`: The `RoleStore` contract dispatcher, responsible for managing roles and permissions within the system.
+- `event_emitter`: The `EventEmitter` contract dispatcher, vital for emitting events and notifications within the blockchain, allowing the tracking of system alterations.
+
+## Functions
+
+### `initialize`
+- **Objective:** Initialize the FeeHandler contract with essential components like `DataStore`, `RoleStore`, and `EventEmitter`.
+
+### `claim_fees`
+- **Objective:** Execute fee claims from specified markets for given tokens.
+
+## Error Handling
+### `FeeError`
+- **ALREADY_INITIALIZED:** Triggered when there is an attempt to initialize an already initialized contract.
+- **INVALID_CLAIM_FEES_INPUT:** Occurs when the lengths of the market and tokens arrays do not match during a fee claim operation.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/gas-module.md b/book/src/smart-contracts-architecture/gas-module.md
index 1accbac3..5b644517 100644
--- a/book/src/smart-contracts-architecture/gas-module.md
+++ b/book/src/smart-contracts-architecture/gas-module.md
@@ -1,7 +1,46 @@
# Gas Module
-The purpose of the gas module is for the execution fee estimation and payments.
+The Gas Module is developed to manage execution fee estimations and payments within the system.
-It contains the following Cairo library files:
+This module comprises the following Cairo library files:
+- [GasUtils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/gas/gas_utils.cairo): Entrusted with the responsibility for execution fee estimation and payments.
-- [GasUtils](https://github.com/keep-starknet-strange/satoru/blob/main/src/gas/gas_utils.cairo): It is responsible for the execution fee estimation and payments
\ No newline at end of file
+## Structures and Types
+
+### `ContractAddress`
+- A specialized type representing the address of a contract within the Starknet network.
+
+## Functions
+
+### `get_min_handle_execution_error_gas`
+- **Objective:** Retrieve the minimal gas required to handle execution errors from the data store.
+
+### `get_execution_gas`
+- **Objective:** Validate that the starting gas is higher than the minimum handle execution gas and return the remaining gas after subtracting the minimum handle error gas.
+
+### `pay_execution_fee`
+- **Objective:** Pays the execution fee to the keeper and refunds any excess amount to the refund receiver.
+
+### `validate_execution_fee`
+- **Objective:** Validate that the provided execution fee is sufficient based on the estimated gas limit.
+
+### `adjust_gas_usage`
+- **Objective:** Adjust the gas usage to ensure keepers are paid a nominal amount.
+
+### `adjust_gas_limit_for_estimate`
+- **Objective:** Adjust the estimated gas limit to ensure the execution fee is sufficient during the actual execution.
+
+### `estimate_execute_deposit_gas_limit`, `estimate_execute_withdrawal_gas_limit`, `estimate_execute_order_gas_limit`
+- **Objective:** Estimate the gas limits for deposits, withdrawals, and orders respectively based on different parameters.
+
+### `pay_execution_fee_deposit`
+- **Objective:** Pay the deposit execution fee to the keeper and refund any excess amount to the refund receiver. It is specifically designed to handle deposit transactions.
+
+### `estimate_execute_increase_order_gas_limit`, `estimate_execute_decrease_order_gas_limit`, `estimate_execute_swap_order_gas_limit`
+- **Objective:** Estimate the gas limits for increase orders, decrease orders, and swap orders respectively, based on different parameters.
+
+## Errors
+
+### `GasError`
+- **INSUFF_EXEC_GAS (`'insufficient_gas_for_execute'`):** Triggered when the starting gas is less than the minimum required to handle execution errors.
+- **INSUFF_EXEC_FEE (`'insufficient_execution_fee'`):** Occurs when the provided execution fee is less than the minimum execution fee calculated based on the estimated gas limit.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/liquidation-module.md b/book/src/smart-contracts-architecture/liquidation-module.md
index 7d859a1a..3d7c89a1 100644
--- a/book/src/smart-contracts-architecture/liquidation-module.md
+++ b/book/src/smart-contracts-architecture/liquidation-module.md
@@ -1,7 +1,41 @@
-# Liquidation module
+# Liquidation Module
-The Liquidation is used to to help with liquidations.
+The Liquidation Module is designed to facilitate and manage liquidations within the system, ensuring stability and solvency of the market.
-It contains the following Cairo library files:
+## Overview
-- [liquidation_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/liquidation/liquidation_utils.cairo): It is responsible for liquidations.
+This module contains the following Cairo library file:
+- [liquidation_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/liquidation/liquidation_utils.cairo): Entrusted with managing liquidations in the network.
+
+## Structures and Types
+
+### `CreateLiquidationOrderParams`
+
+This struct is used within the `create_liquidation_order` function to encapsulate the necessary parameters for creating a liquidation order, thus preventing stack overflow.
+
+- `data_store`: The `DataStore` contract dispatcher providing access to centralized data storage, crucial for storing and retrieving market, position, and order-related information.
+- `event_emitter`: The `EventEmitter` contract dispatcher, essential for emitting events on the blockchain and allowing users and other contracts to monitor system changes.
+- `account`: Represents the address of the account associated with the position to be liquidated.
+- `market`: Specifies the address of the concerned market, aiding in identifying the specific market parameters and states involved.
+- `collateral_token`: Represents the address of the token used as collateral for the position, crucial for determining the liquidation impact.
+- `is_long`: A boolean indicating whether the position is long or short, defining the nature of the liquidation.
+
+## Functions
+
+### `create_liquidation_order`
+
+This function creates a liquidation order for a specific position, ensuring market stability and solvency. The function returns a `felt252` type representing the key of the created order, where `felt252` is a type representing a 252-bit field element.
+
+## Usage Example
+
+```cairo
+// Example of creating a liquidation order
+let params = liquidation_utils::CreateLiquidationOrderParams {
+ data_store: /* ... */,
+ event_emitter: /* ... */,
+ account: /* ... */,
+ market: /* ... */,
+ collateral_token: /* ... */,
+ is_long: /* ... */,
+};
+liquidation_utils::create_liquidation_order(params);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/market-module.md b/book/src/smart-contracts-architecture/market-module.md
new file mode 100644
index 00000000..d959e046
--- /dev/null
+++ b/book/src/smart-contracts-architecture/market-module.md
@@ -0,0 +1,91 @@
+# Market Module
+
+The Market Module helps with trading in different markets. It lets you create markets by choosing specific tokens. This module supports both regular and ongoing trading.
+
+Example markets include:
+
+- ETH/USD: Long collateral as ETH, short collateral as a stablecoin, index token as ETH.
+- BTC/USD: Long collateral as WBTC, short collateral as a stablecoin, index token as BTC.
+- STRK/USD: Long collateral as ETH, short collateral as a stablecoin, index token as STRK.
+
+In each market, liquidity providers can deposit either the long or the short collateral token, or both, to mint liquidity tokens. The module allows for risk isolation by exposing liquidity providers only to the markets they deposit into, enabling potentially permissionless listings.
+
+It contains the following Cairo library files:
+
+- [market.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/market/market.cairo)
+
+## Structures and Types
+
+### `Market`
+
+This struct represents a market with the following fields:
+
+- `market_token`: Address of the market token for the market.
+- `index_token`: Address of the index token for the market.
+- `long_token`: Address of the long token for the market.
+- `short_token`: Address of the short token for the market.
+
+## Functions and Traits
+
+### `IntoMarketToken`
+
+This trait provides a method to get the `MarketToken` contract interface of a market.
+
+### `UniqueIdMarket`
+
+This trait provides a method to compute the unique id of a market based on its parameters.
+
+### `ValidateMarket`
+
+This trait provides methods to validate a market, either by returning a boolean value or by asserting the validity.
+
+## Implementations
+
+### `UniqueIdMarketImpl`
+
+This is the implementation of the `UniqueIdMarket` trait for the `Market` struct, providing a method to compute the unique id of a market.
+
+### `ValidateMarketImpl`
+
+This is the implementation of the `ValidateMarket` trait for the `Market` struct, offering methods to validate the market's state.
+
+### `MarketTokenImpl`
+
+This is the implementation of the `IntoMarketToken` trait for the `Market` struct, providing the `MarketToken` contract interface of a market.
+
+## Errors
+
+The module incorporates a `MarketError` enum to manage market-specific errors, primarily to handle cases involving invalid market parameters. Each constant in the `MarketError` module represents a specific error case in the market module. Here are the defined errors:
+
+- **`MARKET_NOT_FOUND`**: Triggered when the specified market cannot be located within the system.
+- **`DIVISOR_CANNOT_BE_ZERO`**: Raised when an attempt is made to divide by zero.
+- **`INVALID_MARKET_PARAMS`**: Occurs when the parameters provided for the market are invalid.
+- **`OPEN_INTEREST_CANNOT_BE_UPDATED_FOR_SWAP_ONLY_MARKET`**: This error is triggered when there is an attempt to update open interest for a swap-only market.
+- **`MAX_OPEN_INTEREST_EXCEEDED`**: Occurs when the maximum open interest for a market is surpassed.
+- **`EMPTY_ADDRESS_IN_MARKET_TOKEN_BALANCE_VALIDATION`**: Raised when an empty address is found during market token balance validation.
+- **`EMPTY_ADDRESS_TOKEN_BALANCE_VAL`**: Triggered when an empty address is discovered during token balance validation.
+- **`INVALID_MARKET_TOKEN_BALANCE`**: Occurs when the market token balance is found to be invalid.
+- **`INVALID_MARKET_TOKEN_BALANCE_FOR_COLLATERAL_AMOUNT`**: This error is raised when the market token balance for a collateral amount is invalid.
+- **`INVALID_MARKET_TOKEN_BALANCE_FOR_CLAIMABLE_FUNDING`**: Triggered when the market token balance for claimable funding is invalid.
+- **`EmptyAddressInMarketTokenBalanceValidation`**: Occurs when an empty address is encountered during market token balance validation.
+- **`INVALID_POSITION_MARKET`**: Raised when the market for a position is invalid.
+- **`INVALID_COLLATERAL_TOKEN_FOR_MARKET`**: Triggered when an invalid collateral token is provided for the market.
+- **`EMPTY_MARKET`**: Occurs when the market is found to be empty.
+- **`DISABLED_MARKET`**: Triggered when the market is disabled.
+
+Additionally, there is a function `UNABLE_TO_GET_CACHED_TOKEN_PRICE` which panics with a specific message when it is unable to get the cached token price for a given token.
+
+## Usage Example
+
+```cairo
+let market = Market {
+ market_token: /* ContractAddress of the market token */,
+ index_token: /* ContractAddress of the index token */,
+ long_token: /* ContractAddress of the long token */,
+ short_token: /* ContractAddress of the short token */,
+};
+
+// Asserting that the market is valid
+market.assert_valid();
+// Getting the MarketToken contract interface of the market
+let market_token_dispatcher = market.market_token();
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/mock.md b/book/src/smart-contracts-architecture/mock.md
index 341e4583..0699d477 100644
--- a/book/src/smart-contracts-architecture/mock.md
+++ b/book/src/smart-contracts-architecture/mock.md
@@ -1,12 +1,61 @@
-# Mock module
+# Mock Module
-The Mock module is used to store mocked implementation of contracts to use them in tests.
+The Mock Module is essential for testing environments and testnets. It holds mocked implementations of contracts.
-It contains the following Cairo library files:
+## Cairo Library Files
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/mock/error.cairo): Contains error codes pertinent to the Mock Module.
-- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/mock/error.cairo): Contains the error codes of the module.
+## Smart Contracts
-It contains the following smart contracts:
+### [ReferralStorage.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/mock/referral_stoage.cairo)
+- **Key Functions:**
+ - Manages Set and Get functions for handling referral-related data and operations.
+ - Allows the registration and management of referral codes, setting of trader and referrer tiers, and handling of referral-related data with robust error handling mechanisms.
-- [ReferralStorage.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/mock/referral_stoage.cairo): Set and Get of functions for managing referral-related data and operations.
-- [Governable.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/governable.cairo): Referral storage for testing and testnets
+- **Interface: IReferralStorage**
+ - **Functions:**
+ 1. `initialize`: Initializes the contract state with the given event_emitter_address.
+ 2. `only_handler`: Ensures that the caller is a handler.
+ 3. `set_handler`: Sets an address as a handler, controlling the active status of handlers.
+ 4. `set_referrer_discount_share`: Sets the trader discount share for an affiliate.
+ 5. `set_trader_referral_code_by_user`: Sets the referral code for a trader.
+ 6. `register_code`: Registers a referral code.
+ 7. `set_code_owner`: Sets the owner of a referral code.
+ 8. `code_owners`: Gets the owner of a referral code.
+ 9. `trader_referral_codes`: Gets the referral code of a trader.
+ 10. `referrer_discount_shares`: Gets the trader discount share for an affiliate.
+ 11. `referrer_tiers`: Gets the tier level of an affiliate.
+ 12. `get_trader_referral_info`: Gets the referral info for a trader.
+ 13. `set_trader_referral_code`: Sets the referral code for a trader.
+ 14. `set_tier`: Sets the values for a tier.
+ 15. `set_referrer_tier`: Sets the tier for an affiliate.
+ 16. `gov_set_code_owner`: Sets the owner for a referral code by the governor.
+ 17. `tiers`: Gets the tier values for a tier level.
+
+### [Governable.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/governable.cairo)
+- **Key Functions:**
+ - Provides functionalities to manage governance-related operations and states.
+ - Ensures that only authorized entities can perform certain operations, enhancing the security of the contract.
+
+- **Interface: IGovernable**
+ - **Functions:**
+ 1. `initialize`: Initializes the contract state with the given event_emitter_address.
+ 2. `only_gov`: Ensures that the caller has governance permissions; triggers panic if unauthorized.
+ 3. `transfer_ownership`: Initiates the transfer of contract governance to a new address; only the current governance address can call this.
+ 4. `accept_ownership`: Accepts the governance of the contract; only the pending governance address can call this.
+
+## Structures and Types
+### `ReferralTier`
+ - Represents a referral tier, holding information such as total rebate and discount share for the tier.
+
+### `ContractState`
+ - Holds the contract state, facilitating the storage and retrieval of state information like event emitters, governance, and handler status.
+
+## Errors
+- The module defines a `MockError` to handle mock-specific errors with constants representing specific error cases in the Mock module, such as `INVALID_TOTAL_REBATE`, `INVALID_DISCOUNT_SHARE`, and `FORBIDDEN`.
+
+## Usage Example
+```cairo
+// Example of registering a referral code
+let code: felt252 = /* ... */;
+referral_storage::register_code(code);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/nonce-module.md b/book/src/smart-contracts-architecture/nonce-module.md
index 7a1ce5d1..65b52411 100644
--- a/book/src/smart-contracts-architecture/nonce-module.md
+++ b/book/src/smart-contracts-architecture/nonce-module.md
@@ -1,7 +1,56 @@
# Nonce Module
-The purpose of the nonce module is to maintain a progressively increasing nonce value. This value plays a crucial role in the generation of keys.
+The Nonce Module keeps track of a number that goes up one at a time, which is crucial for creating unique keys. This is really important to make sure every operation in the system is unique.
-It contains the following smart contracts:
+It contains the following smart contract:
-- [NonceUtils](https://github.com/keep-starknet-strange/satoru/blob/main/src/nonce/nonce_utils.cairo): The main smart contract of the module. It is used to maintain a progressively increasing nonce value. This value plays a crucial role in the generation of keys.
\ No newline at end of file
+- [NonceUtils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/nonce/nonce_utils.cairo): The principal smart contract in the module, responsible for sustaining an incrementing nonce value crucial for key generation.
+
+## Structures and Types
+
+### `IDataStoreDispatcher`
+- The dispatcher for `DataStore` contract provides methods to interact with the centralized data storage, essential for storing and retrieving nonce-related information.
+
+## Functions
+
+### `get_current_nonce`
+- Retrieves the current nonce value from the data store.
+- **Arguments:**
+ - `data_store`: The data store to use.
+- **Returns:**
+ - The current nonce value.
+
+### `increment_nonce`
+- Increments the current nonce value in the data store.
+- **Arguments:**
+ - `data_store`: The data store to use.
+- **Returns:**
+ - The new nonce value.
+
+### `get_next_key`
+- Computes a `felt252` hash using the next nonce and can also use the nonce directly as a key.
+- **Arguments:**
+ - `data_store`: The data store to use.
+- **Returns:**
+ - The `felt252` hash using the next nonce value.
+
+## Core Logic
+
+### `compute_key`
+- Computes a key using the provided `data_store_address` and `nonce`.
+- **Arguments:**
+ - `data_store_address`: The address of the data store.
+ - `nonce`: The nonce value.
+- **Returns:**
+ - A `felt252` key.
+
+## Errors
+
+The module defines specific errors to handle nonce-specific anomalies and invalid operations, ensuring smooth and accurate operations within the module.
+
+## Usage Example
+
+```cairo
+// Example of getting the next key
+let data_store: IDataStoreDispatcher = /* ... */;
+let next_key: felt252 = nonce_utils::get_next_key(data_store);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/oracle-module.md b/book/src/smart-contracts-architecture/oracle-module.md
index c75363bd..84fcb31e 100644
--- a/book/src/smart-contracts-architecture/oracle-module.md
+++ b/book/src/smart-contracts-architecture/oracle-module.md
@@ -7,7 +7,7 @@ The purpose of the oracle module is to validate and store signed values.
Representing the prices in this way allows for conversions between token amounts
and fiat values to be simplified, e.g. to calculate the fiat value of a given
number of tokens the calculation would just be: `token amount * oracle price`,
-to calculate the token amount for a fiat value it would be: `fiat value oracle price`.
+to calculate the token amount for a fiat value it would be: `fiat value / oracle price`.
The trade-off of this simplicity in calculation is that tokens with a small USD
price and a lot of decimals may have precision issues it is also possible that
@@ -110,4 +110,4 @@ It contains the following files:
- [oracle_modules.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/oracle/oracle_modules.cairo): Modifiers for oracles.
- [oracle_store.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/oracle/oracle_modules.cairo): Storage for oracles.
- [oracle_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/oracle/oracle_utils.cairo): Contains utility structs and functions for Oracles.
-- [oracle.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/oracle/oracle_modules.cairo): Main oracle smart contract.
+- [oracle.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/oracle/oracle_modules.cairo): Main oracle smart contract.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/order-module.md b/book/src/smart-contracts-architecture/order-module.md
index f35cbed5..0ef8d58d 100644
--- a/book/src/smart-contracts-architecture/order-module.md
+++ b/book/src/smart-contracts-architecture/order-module.md
@@ -1,19 +1,89 @@
-# Order module
+# Order Module
-The order module is reponsible for the vault order, functions related to orders.
+The Order Module is key for handling orders in the system. Itβs important for changing, processing, and looking after orders.
-It contains the following smart contracts:
+## Overview
-- [OrderVault](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order_vault.cairo): Vault for orders
+This module centralizes the logic related to orders, managing various aspects including processing increasing and decreasing orders, structuring orders, and providing utilities for common order-related operations. Its design allows developers to interact with, modify, or extend the functionalities with ease and precision.
-It contains the following Cairo library files:
+## Smart Contracts
-- [base_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/base_order_utils.cairo): This library comprises a collection of frequently used order-related functions, designed to facilitate common operations.
+- [OrderVault.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order_vault.cairo): Acts as a secure vault for orders, ensuring their safe storage and accessibility.
-- [decrease_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/decrease_order_utils.cairo): Library for functions to help with processing a decreasing order.
+## Cairo Library Files
-- [increase_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/increase_order_utils.cairo): Library for functions to help with processing a increasing order.
+### [base_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/base_order_utils.cairo)
+A collection of essential functions facilitating common order-related operations, enhancing code reusability and organization.
-- [order.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order.cairo): Struct for orders
+### [decrease_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/decrease_order_utils.cairo)
+Contains functions aiding in the processing of decreasing orders, ensuring their accurate and efficient handling.
-- [order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order.cairo): Library for order functions.
+### [increase_order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/increase_order_utils.cairo)
+Comprises functions to assist in processing increasing orders, maintaining precision and efficiency in operations.
+
+### [order.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order.cairo)
+Defines the structure for orders, serving as a blueprint for order objects within the system.
+
+### [order_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/order/order_utils.cairo)
+Encompasses various order-related functions, offering utilities to streamline order processing and management.
+
+## Detailed Structure and Types
+
+### `Order`
+- Represents the blueprint for creating order objects, defining the properties and characteristics of an order within the system.
+
+#### Properties
+- **key**: A unique identifier of the order of type `felt252`.
+- **order_type**: Specifies the type of order from the enumerated `OrderType`.
+- **decrease_position_swap_type**: Specifies the type of swap for decreasing position orders from the enumerated `DecreasePositionSwapType`.
+- **account**: The account of the user creating the order, represented as a `ContractAddress`.
+- **receiver**: The receiver for any token transfers, represented as a `ContractAddress`.
+- **callback_contract**: The contract to call for callbacks, represented as a `ContractAddress`.
+- **ui_fee_receiver**: The UI fee receiver, represented as a `ContractAddress`.
+- **market**: The trading market's contract address.
+- **initial_collateral_token**: The initial collateral token for increase orders, represented as a `ContractAddress`.
+- **swap_path**: An array of market addresses to swap through.
+- **size_delta_usd**: The requested change in position size, represented as `u128`.
+- **initial_collateral_delta_amount**: Represents different amounts based on the order, either the amount of the initialCollateralToken sent in by the user for increase orders, the amount of the position's collateralToken to withdraw for decrease orders, or the amount of initialCollateralToken sent in for the swap, represented as `u128`.
+- **trigger_price**: The trigger price for non-market orders, represented as `u128`.
+- **acceptable_price**: The acceptable execution price for increase/decrease orders, represented as `u128`.
+- **execution_fee**: The execution fee for keepers, represented as `u128`.
+- **callback_gas_limit**: The gas limit for the callbackContract, represented as `u128`.
+- **min_output_amount**: The minimum output amount for decrease orders and swaps, represented as `u128`.
+- **updated_at_block**: The block at which the order was last updated, represented as `u64`.
+- **is_long**: Boolean flag indicating whether the order is for a long or short.
+- **is_frozen**: Boolean flag indicating whether the order is frozen.
+
+### Enumerations
+#### `OrderType`
+Enumerates the various types of orders that can be created in the system, including MarketSwap, LimitSwap, MarketIncrease, LimitIncrease, MarketDecrease, LimitDecrease, StopLossDecrease, and Liquidation.
+
+#### `DecreasePositionSwapType`
+Indicates whether the decrease order should swap the pnl token to collateral token or vice versa, with possible values being NoSwap, SwapPnlTokenToCollateralToken, and SwapCollateralTokenToPnlToken.
+
+#### `SecondaryOrderType`
+Further differentiates orders, with possible values being None and Adl.
+
+## Core Functionalities and Methods
+
+### `touch`
+Updates the `updated_at_block` property of the order to the current block number.
+
+### `OrderTypeInto`
+Converts the enumerated `OrderType` to a `felt252` type.
+
+### `OrderTypePrintImpl`
+Prints the corresponding string representation of the `OrderType`.
+
+### `SecondaryOrderTypePrintImpl`
+Prints the corresponding string representation of the `SecondaryOrderType`.
+
+### `DecreasePositionSwapTypePrintImpl`
+Prints the corresponding string representation of the `DecreasePositionSwapType`.
+
+### `DefaultOrder`
+Provides a default implementation for creating a new `Order` instance with default values.
+
+## Errors
+
+The module delineates specific error cases to manage anomalies and invalid operations related to orders, ensuring seamless execution of order operations and facilitating troubleshooting and debugging.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/overview.md b/book/src/smart-contracts-architecture/overview.md
index 1a2f8873..b62de5e3 100644
--- a/book/src/smart-contracts-architecture/overview.md
+++ b/book/src/smart-contracts-architecture/overview.md
@@ -3,6 +3,11 @@
![Schema](../assets/satoru-diagram.png)
Satoru high-level modules overview.
+# Protocol Infrastructure Overview
+
+![Schema](../assets/satoru-infra.png)
+Satoru infrastucture overview.
+
## Two steps actions in Satoru
Satoru employs a two-step approach for critical actions like Deposit, Withdrawal, and Order execution. This method ensures enhanced security and guards against front-running risks.
diff --git a/book/src/smart-contracts-architecture/position-module.md b/book/src/smart-contracts-architecture/position-module.md
index 2cda6f0f..379c3e5a 100644
--- a/book/src/smart-contracts-architecture/position-module.md
+++ b/book/src/smart-contracts-architecture/position-module.md
@@ -4,7 +4,7 @@ The purpose of the position module is to help with management of positions.
## Fees in position
-Borrowing fees for position require only a borrowing_factor to track. An example on how this works is if the global cumulative_borrowing_factor is 10020% a position would be opened with borrowingFactor as 10020%. After some time, if the cumulative\_\_borrowing_factor is updated to 10025% the position would owe 5% of the position size as borrowing fees. The total pending borrowing fees of all positions is factored into the calculation of the pool value for LPs. When a position is increased or decreased, the pending borrowing fees for the position is deducted from the position's
+Borrowing fees for position require only a borrowing_factor to track. An example on how this works is if the global cumulative_borrowing_factor is 10020% a position would be opened with borrowingFactor as 10020%. After some time, if the cumulative_borrowing_factor is updated to 10025% the position would owe 5% of the position size as borrowing fees. The total pending borrowing fees of all positions is factored into the calculation of the pool value for LPs. When a position is increased or decreased, the pending borrowing fees for the position is deducted from the position's
collateral and transferred into the LP pool.
The same borrowing fee factor tracking cannot be applied for funding fees as those calculations consider pending funding fees based on the fiat value of the position sizes.
diff --git a/book/src/smart-contracts-architecture/price-module.md b/book/src/smart-contracts-architecture/price-module.md
new file mode 100644
index 00000000..144f2636
--- /dev/null
+++ b/book/src/smart-contracts-architecture/price-module.md
@@ -0,0 +1,72 @@
+# Price Module
+
+The Price Module helps manage everything related to prices. It organizes how to handle lowest and highest prices and makes working with these prices easier.
+
+## Cairo Library Files
+
+### [price.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/price/price.cairo)
+Defines the `Price` struct and associated methods, serving as a utility to streamline price-related operations in contracts.
+
+## Structures and Types
+
+### `Price`
+
+This struct holds the minimum and maximum prices and provides a set of methods to perform various operations using these prices.
+
+- **min**: The minimum price, represented as `u128`.
+- **max**: The maximum price, represented as `u128`.
+
+## Trait and Implementations
+
+### `PriceTrait`
+
+This trait defines a set of methods that can be performed on a `Price` struct.
+
+#### Methods
+
+- **mid_price**:
+ - Returns the average of the min and max values of the `Price` struct.
+ - Arguments:
+ - `self`: The `Price` struct.
+ - Returns: The average of the min and max values as `u128`.
+
+- **pick_price**:
+ - Picks either the min or max value based on the `maximize` parameter.
+ - Arguments:
+ - `self`: The `Price` struct.
+ - `maximize`: If true, picks the max value. Otherwise, picks the min value.
+ - Returns: The min or max value as `u128`.
+
+- **pick_price_for_pnl**:
+ - Picks the min or max price depending on whether it is for a long or short position, and whether the pending pnl should be maximized or not.
+ - Arguments:
+ - `self`: The `Price` struct.
+ - `is_long`: Whether it is for a long or a short position.
+ - `maximize`: Whether the pending pnl should be maximized or not.
+ - Returns: The min or max price as `u128`.
+
+### `PriceImpl`
+
+This implementation block provides concrete implementations for the methods defined in the `PriceTrait` for a `Price` struct.
+
+### `PriceZeroable`
+
+This implementation block provides methods to create a zero `Price` struct and check whether a `Price` struct is zero or non-zero.
+
+#### Methods
+
+- **zero**:
+ - Returns a `Price` struct with min and max values set to 0.
+ - Returns: A zero `Price` struct.
+
+- **is_zero**:
+ - Checks whether the `Price` struct is zero.
+ - Arguments:
+ - `self`: The `Price` struct.
+ - Returns: A boolean value indicating whether the `Price` struct is zero.
+
+- **is_non_zero**:
+ - Checks whether the `Price` struct is non-zero.
+ - Arguments:
+ - `self`: The `Price` struct.
+ - Returns: A boolean value indicating whether the `Price` struct is non-zero.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/pricing-module.md b/book/src/smart-contracts-architecture/pricing-module.md
index e09d4b93..6ebca3e6 100644
--- a/book/src/smart-contracts-architecture/pricing-module.md
+++ b/book/src/smart-contracts-architecture/pricing-module.md
@@ -50,4 +50,4 @@ It contains the following Cairo library files:
- [position_pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/pricing/position_pricing_utils.cairo): Library for position pricing functions.
- [pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/pricing/pricing_utils.cairo): Library for pricing functions.
-- [swap_pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/pricing/swap_pricing_utils.cairo): Library for pricing functions linked to swaps.
+- [swap_pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/pricing/swap_pricing_utils.cairo): Library for pricing functions linked to swaps.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/reader-module.md b/book/src/smart-contracts-architecture/reader-module.md
index 28ba3e7f..d63c9c51 100644
--- a/book/src/smart-contracts-architecture/reader-module.md
+++ b/book/src/smart-contracts-architecture/reader-module.md
@@ -1,9 +1,10 @@
# Reader Module
-The purpose of this module is to get financial market data and trading utility library.
+The Reader Module gets market data and is like a utility library for trading. Itβs especially important for markets that need lots of calculations and data for operating and evaluating the market.
-It contains the following files:
+## Cairo Library Files
-- [reader_pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/reader/reader_pricing_utils.cairo): Utility functions for trading price, impact, and fee calculations.
+The module contains the following Cairo files:
+- [reader_pricing_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/reader/reader_pricing_utils.cairo): Utility functions for trading price calculations, impact, and fees.
- [reader_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/reader/reader_utils.cairo): External utility functions for trading operations.
-- [reader.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/reader/reader.cairo): Library for reading and calculating financial market data and trading operations.
+- [reader.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/reader/reader.cairo): Library for reading and calculating financial market data and trading operations.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/referral-module.md b/book/src/smart-contracts-architecture/referral-module.md
index af5840de..ed0ba953 100644
--- a/book/src/smart-contracts-architecture/referral-module.md
+++ b/book/src/smart-contracts-architecture/referral-module.md
@@ -1,8 +1,42 @@
-# Referral module
+# Referral Module
-The referral module is responsible for managing protocol users affiliations with discount and rebates.
+The Referral Module handles user referrals, giving discounts and paybacks. Itβs key for encouraging people to bring in others and rewarding them for helping the platform grow.
It contains the following Cairo library files:
-- [referral_tier.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/referral_tier.cairo): Contains the referral tier struct.
-- [referral_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/referral_utils.cairo): Contains referral utility functions.
+- [referral_tier.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/referral_tier.cairo): Defines the `ReferralTier` struct and contains related functionalities.
+- [referral_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/referral/referral_utils.cairo): Houses various referral utility functions essential for managing referrals within the platform.
+
+## Structures and Types
+
+### `ReferralTier`
+This struct encapsulates the total rebate for the tier, which is the sum of the affiliate reward and trader discount, and the share of the total rebate designated for traders.
+
+## Functions
+
+### `set_trader_referral_code`
+This function sets the referral code for a trader and is vital for linking traders to their referrers, ensuring that the correct users receive their due rewards.
+
+### `increment_affiliate_reward`
+It increments the affiliate's reward balance by a specified delta, updating the reward balance and emitting an event signaling the update.
+
+### `get_referral_info`
+Retrieves the referral information for a specified trader, returning the referral code, the affiliate's address, the total rebate, and the discount share. It plays a crucial role in fetching referral details needed for various operations, like calculating rebates and discounts.
+
+### `claim_affiliate_reward`
+Allows claiming of the affiliate reward. It returns the reward amount and updates relevant balances and states to reflect the claimed reward.
+
+## Errors
+
+Specific error handling would be defined to manage any anomalies in referral operations, such as invalid referral codes, non-existent affiliates, etc., ensuring the robustness and reliability of the referral system.
+
+## Imports
+
+### Core Library Imports
+- `starknet`: Used for core functionalities and structures in Starknet contracts.
+- Several other local imports from the `satoru` project for various functionalities like data storage, event emission, and market utilities.
+
+### Local Imports from `satoru` project
+- `referral_storage`: For managing referral-related data storage operations.
+- `data_store`: Centralized data storage used for storing and retrieving information about referrals, rewards, etc.
+- `event_emitter`: Utilized for emitting events on the blockchain, allowing users and other contracts to track changes in the system.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/role-module.md b/book/src/smart-contracts-architecture/role-module.md
index 3853cabc..fc465abe 100644
--- a/book/src/smart-contracts-architecture/role-module.md
+++ b/book/src/smart-contracts-architecture/role-module.md
@@ -1,12 +1,74 @@
-# Role module
+# Role Module
-The role module is responsible for role-based access control.
+The Role Module is crucial for managing who has access to what, controlling the assignment and removal of roles to different accounts in the system.
-It contains the following smart contracts:
+It consists of the following smart contracts and Cairo library files:
-- [RoleStore](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/role_store.cairo): The main smart contract of the module. It is responsible for storing the roles of the protocol and for managing the access control.
+- [RoleStore](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/role_store.cairo): The central contract of the module, focusing on storing roles and managing access control across the protocol.
+- [role.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/role.cairo): Holds the definitions of different roles existing within the protocol.
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/error.cairo): Encompasses the error codes specific to this module.
+- [role_module.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/role_module.cairo): Implements the `RoleModule` contract interface, focusing on role validation and interaction with `RoleStore`.
-It contains the following Cairo library files:
+### Features of role_module.cairo
-- [role.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/role.cairo): Contains the different roles of the protocol.
-- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/role/error.cairo): Contains the error codes of the module.
+- **Initialization**: It initializes the role store with the provided address.
+- **Role Validation Functions**: Provides a set of functions like `only_timelock_admin`, `only_controller`, etc., each validating a specific role in the protocol.
+- **Role Verification**: Utilizes `RoleStore` to verify if an account holds the specified role, ensuring secure and accurate role-based access control.
+- **Access Restriction**: Employs role validation to restrict access to specific functions, maintaining the protocol's security and integrity.
+
+## Roles Defined
+
+The following roles are defined within the protocol:
+
+- `ADMIN`
+- `TIMELOCK_ADMIN`
+- `TIMELOCK_MULTISIG`
+- `CONFIG_KEEPER`
+- `CONTROLLER`
+- `ROUTER_PLUGIN`
+- `MARKET_KEEPER`
+- `FEE_KEEPER`
+- `ORDER_KEEPER`
+- `FROZEN_ORDER_KEEPER`
+- `PRICING_KEEPER`
+- `LIQUIDATION_KEEPER`
+- `ADL_KEEPER`
+
+These roles are represented by constants defined in `role.cairo`, and they are essential in maintaining the integrity and functionality of the system by granting specific permissions to different accounts.
+
+## Functions
+
+### `has_role`
+Determines whether a given account holds a specified role.
+### `grant_role`
+Assigns a particular role to a specific account.
+### `revoke_role`
+Removes a designated role from a given account.
+### `assert_only_role`
+Ensures that a specified account holds only a particular role, reverting if the condition is not met.
+### `get_role_count`
+Returns the number of roles stored within the contract.
+### `get_roles`
+Retrieves the keys of roles stored within the contract, based on the provided range of indices.
+### `get_role_member_count`
+Returns the number of members assigned to a specified role.
+### `get_role_members`
+Retrieves the members of a specified role, based on the given range of indices.
+
+## Events
+
+### `RoleGranted`
+Emitted when a role is assigned to an account.
+### `RoleRevoked`
+Emitted when a role is removed from an account.
+
+## Errors
+
+### `UNAUTHORIZED_ACCESS`
+Indicates that an operation was attempted by an account lacking the necessary role.
+
+## Example
+
+```cairo
+// Granting a role to an account
+RoleStore.grant_role(account: ContractAddress, role_key: 'ADMIN')
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/router-module.md b/book/src/smart-contracts-architecture/router-module.md
index 52049d9d..e2926564 100644
--- a/book/src/smart-contracts-architecture/router-module.md
+++ b/book/src/smart-contracts-architecture/router-module.md
@@ -1,6 +1,6 @@
# Router module
-The exchange router is where users utilize the router to initiate token transactions, exchanges, and transfers.
+The exchange router is the place where users go to start token trades, swaps, and moves.
## Front-running solution
@@ -39,4 +39,4 @@ Prices are provided by an off-chain oracle system:
It contains the following smart contracts:
- [Router](https://github.com/keep-starknet-strange/satoru/blob/main/src/router/router.cairo): Users will approve this router for token expenditures.
-- [ExchangeRouter](https://github.com/keep-starknet-strange/satoru/blob/main/src/router/exchange_router.cairo): Router for exchange functions, supports functions which require token transfers from the user.
+- [ExchangeRouter](https://github.com/keep-starknet-strange/satoru/blob/main/src/router/exchange_router.cairo): Router for exchange functions, supports functions which require token transfers from the user.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/swap-module.md b/book/src/smart-contracts-architecture/swap-module.md
index f0e9b22c..a07f1114 100644
--- a/book/src/smart-contracts-architecture/swap-module.md
+++ b/book/src/smart-contracts-architecture/swap-module.md
@@ -1,11 +1,65 @@
-# Swap module
+# Swap Module
-The swap module is reponsible for swaping.
+The Swap Module is crucial for switching one token for another in the system. It makes sure the swap meets market conditions, adjusting for things like price changes and fees.
-It contains the following smart contracts:
+## Smart Contracts
-- [SwapHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/swap/swap_handler): Smart contract to handle swaps.
+- [SwapHandler](https://github.com/keep-starknet-strange/satoru/blob/main/src/swap/swap_handler): This contract is responsible for handling swaps, ensuring that only authorized entities can invoke the swap function. It validates the swap parameters and interacts with the `swap_utils` to perform the swap.
-It contains the following Cairo library files:
+## Cairo Library Files
-- [swap_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/swap/swap_utils.cairo): It is responsible for swaping.
+- [swap_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/swap/swap_utils.cairo): Implements the logic for performing swaps, including validating markets, calculating price impacts, applying fees, and transferring tokens.
+
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/swap/error.cairo): Defines errors specific to the Swap Module, handling cases like insufficient output amount, invalid input token, and duplicated market in swap path.
+
+## Structures and Types
+
+### `SwapParams`
+This struct is used to pass parameters needed for executing a swap. It includes fields like:
+- `data_store`: Provides access to on-chain data storage.
+- `event_emitter`: Enables the emission of events.
+- `oracle`: Provides access to price data from oracles.
+- `bank`: Provides the funds for the swap.
+- `token_in`: The address of the token being swapped.
+- `amount_in`: The amount of the token being swapped.
+- `swap_path_markets`: An array specifying the markets in which the swap should be executed.
+- `min_output_amount`: The minimum amount of tokens that should be received as part of the swap.
+- `receiver`: The address where the swapped tokens should be sent.
+
+### `SwapCache`
+This struct caches data during a swap operation, including token addresses, prices, amounts, and price impacts.
+
+## Functions
+
+### `swap`
+Executes a swap based on the given `SwapParams`, returning the address of the received token and the amount of the received token. It handles edge cases, such as zero amount in or empty swap path markets, and applies the swap to single or multiple markets as specified in the `swap_path_markets`.
+
+### `_swap`
+Performs a swap on a single market, dealing with various conditions like token validity, price impact, and fees, and returns the token and amount that were swapped.
+
+## Errors
+
+### `SwapError`
+Handles errors like:
+- `INSUFFICIENT_OUTPUT_AMOUNT`: Triggered when the output amount is less than the minimum specified.
+- `INVALID_TOKEN_IN`: Raised when the input token is not valid.
+- `SWAP_PRICE_IMPACT_EXCEEDS_AMOUNT_IN`: Occurs when the price impact is more than the amount in.
+- `DUPLICATED_MARKET_IN_SWAP_PATH`: Triggered when there is a duplicate market in the swap path.
+
+## Usage Example
+
+```cairo
+let params = swap_utils::SwapParams {
+ data_store: /* ... */,
+ event_emitter: /* ... */,
+ oracle: /* ... */,
+ bank: /* ... */,
+ key: /* ... */,
+ token_in: /* ... */,
+ amount_in: /* ... */,
+ swap_path_markets: /* ... */,
+ min_output_amount: /* ... */,
+ receiver: /* ... */,
+ ui_fee_receiver: /* ... */,
+};
+swap_utils::swap(params);
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/utils-module.md b/book/src/smart-contracts-architecture/utils-module.md
index c8eaa9e6..98b2881f 100644
--- a/book/src/smart-contracts-architecture/utils-module.md
+++ b/book/src/smart-contracts-architecture/utils-module.md
@@ -1,27 +1,45 @@
# Utils module
-The Utils module is a various collection of utility functions and tools designed to streamline various tasks within the protocol. This module serves as a repository for functions that do not fit into specific categories but are essential for enhancing the efficiency and readability of the codebase.
+The Utils module is like a toolbox, filled with different helpful functions and tools that make tasks in the protocol easier. Itβs a place for essential functions that donβt fit elsewhere but make the code clearer and more efficient.
It contains the following files:
-- [array.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/array.cairo): Helps with array manipulation.
+- [account_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/account_utils.cairo): This file is like a helper in the project, it has functions to check accounts and receivers in the system. It uses methods like `validate_account` and `validate_receiver` to make sure accounts in operations are valid and real, making interactions within the system safer and more secure. This checking is important to avoid mistakes and weaknesses from invalid or empty account interactions.
-- [basic_multicall.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Helps with multicall.
+- [array.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/array.cairo): This file is a helper in the project, it has a bunch of functions for working with lists of items (arrays), which is important for managing data within the contract. It has functions like `get_felt252` and `get_u128` to safely get items from a list, and others like `are_eq`, `are_gt`, `are_gte`, `are_lt`, `are_lte` to compare items in the list to a certain value. This file is really important to make sure list operations are done safely and quickly, avoiding possible mistakes.
-- [bits.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Bits constants.
+- [basic_multicall.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/basic_multicall.cairo): This utilityβs job is to handle and run groups of function calls on a contract, letting many actions happen in one go. Itβs really important for saving on gas and making smart contract interactions more efficient. The `multicall` function in this file takes a list of function calls and runs them one after the other.
-- [calc.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Various calculations.
+- [bits.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/bits.cairo): This file has constants like `BITMASK_8`, `BITMASK_16`, `BITMASK_32`, and `BITMASK_64` that represent different sizes of binary words, used to do bit-level actions like shifting and changing bits on `u128` type values in the contract's code. They are really important for accurately changing binary data at a low level.
-- [enumerable_values.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Extends EnumerableSet.
+- [calc.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/calc.cairo): This file has many utility functions to do different math calculations and change types. It has functions for dividing, adding numbers with specific types, finding the absolute difference between two numbers, and adding and subtracting within limits to avoid going too high or too low. It also has functions to change between different types of numbers, making sure calculations in the contract's code are accurate and safe.
-- [global_reentrancy_guard.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Reentrancy security on a global level.
+- [enumerable_set.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/enumerable_set.cairo): This file creates a special `Set` structure for handling collections of unique items. It lets you make new sets, add and remove items, check if an item is in a set, access items in specific spots, and get all items as a list. It has special versions for `felt252`, `ContractAddress`, and `u128` types, making it adaptable and accurate for different kinds of data in the protocol. The set operations in this file are really important for different parts of the project, helping manage unique collections efficiently and neatly.
-- [hash.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Hash utils.
+- [enumerable_values.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/enumerable_values.cairo): This file is like an add-on to `EnumerableSet`, possibly offering more and specialized features to manage enumerable sets in the system. It has placeholder methods meant to give back lists of specific types of values (`felt252`, `ContractAddress`, `u128`) from a set, between certain start and end points.
-- [precision.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Precisions utils.
+- [error_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/error_utils.cairo): This file is dedicated to providing functionalities related to error handling within the system.
-- [store_contract_address_array.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Implementation of store for Array of ContractAddress.
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/error.cairo): This file defines constants for various types of errors, serving as standardized error messages or codes that can be referenced throughout the system to indicate specific error conditions.
-- [u128_mask.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Mask function.
+- [global_reentrancy_guard.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/global_reentrancy_guard.cairo): This file puts in place a high-level protection to keep smart contract functions safe from reentrancy attacks. It uses a global flag, `REENTRANCY_GUARD_STATUS`, to show if a secured function is running, and has `non_reentrant_before` and `non_reentrant_after` methods to control this flag, stopping harmful reentrant calls and making sure the smart contract runs consistently.
-- [validate_account.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/keys.cairo): Helps validating accounts.
+- [hash.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/hash.cairo): This file has utility functions for creating hashes, specifically with the Poseidon hash function. It has a function, `hash_poseidon_single`, that lets you hash a single `felt252` value using Poseidon, making sure data stays intact and meeting the cryptographic needs in the smart contract.
+
+- [i128_test_storage_contract.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/i128_test_storage_contract.cairo): This file creates a Starknet contract to test storing and getting `i128` values in the contract state. Itβs a testing tool to make sure `i128` values are handled correctly in the smart contract environment.
+
+- [i128.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/i128.cairo): This file has ways to work with `i128` (signed 128-bit integers) in Cairo, including doing math operations, turning them into strings and back, and managing storage, allowing for precise and efficient use of `i128` values in Starknet smart contracts.
+
+- [precision.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/precision.cairo): This offers utility functions for detailed math and changing units, helping with accurate calculations and conversions between different measures, like from float to wei, applying factors, and managing rounding in the Satoru Starknet smart contract environment.
+
+- [serializable_dict.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/serializable_dict.cairo): This file defines the SerializableFelt252Dict structure that allows us to use a Felt252Dict and serialize/deserialize it.
+
+- [span32.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/span32.cairo): Provides utility functions for managing and manipulating fixed-size arrays (span32). A wrapper around Span type with a maximum size of 32. Used to prevent size overflow when storing Span.
+
+- [starknet_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/starknet_utils.cairo): This puts in place fake utilities to mimic Starknet environment features, like `gasleft` and `tx.gasprice`, in the Satoru Starknet smart contract environment. These functions give back set values based on the given parameters, allowing a way to mimic Starknet gas actions during testing and development.
+
+- [store_arrays.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/store_arrays.cairo): This gives ways to read and write different kinds of lists, including lists of `ContractAddress`, `Market`, `Price`, `u128`, `u64`, and `felt252`, to and from Starknet storage. This tool helps in storing different kinds of data in an organized way, allowing easy access and changes, which are key for the smart contracts in the Satoru project to work.
+
+- [traits.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/traits.cairo): This file has a way to make a default `ContractAddress` type from the Starknet library. It uses the `Default` trait to give a method, `default()`, that returns a `ContractAddress` set to `0`. This is useful when you need to make a `ContractAddress` with a default value when there is no specific address given.
+
+- [u128_mask.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/utils/u128_mask.cairo): This file creates a `Mask` structure to check if a given index is unique within a range of 128 bits. The `Mask` has a `bits` field representing a 128-bit unsigned number. The `validate_unique_and_set_index` function checks if the bit at a specific index is unique and not set; if itβs already set or out of bounds, it will cause an error. If not, it sets the bit at that index, showing that this index is now taken. This tool is useful for managing and confirming the uniqueness of indices in a 128-bit range.
\ No newline at end of file
diff --git a/book/src/smart-contracts-architecture/withdrawal-module.md b/book/src/smart-contracts-architecture/withdrawal-module.md
index 3c0efffb..1771968a 100644
--- a/book/src/smart-contracts-architecture/withdrawal-module.md
+++ b/book/src/smart-contracts-architecture/withdrawal-module.md
@@ -1,13 +1,92 @@
-# Withdrawal module
+# Withdrawal Module
-The withdrawal module is responsible for managing withdrawals.
+The Withdrawal Module role is to manage the operations related to withdrawals.
-It contains the following smart contracts:
+## Smart Contracts
-- [WithdrawalVault](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal_vault.cairo): Vault for withdrawals.
+### [WithdrawalVault](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal_vault.cairo)
+The WithdrawalVault is the vault specifically designed for withdrawals, ensuring the secure management of funds during the withdrawal processes.
-It contains the following Cairo library files:
+## Cairo Library Files
-- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/error.cairo): Contains the error codes of the module.
-- [withdrawal_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal_utils.cairo): Contains withdrawal utility functions.
-- [withdrawal.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal.cairo): Contains withdrawal struct.
+- [error.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/error.cairo): Holds the module-specific error codes.
+- [withdrawal_utils.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal_utils.cairo): Encapsulates withdrawal-related utility functions.
+- [withdrawal.cairo](https://github.com/keep-starknet-strange/satoru/blob/main/src/withdrawal/withdrawal.cairo): Defines the structures related to withdrawal.
+
+### Withdrawal Creation and Execution
+In this module, withdrawals can be created through the `create_withdrawal` function, which needs parameters such as the account initiating the withdrawal, the receiver of the tokens, and various other details related to the withdrawal.
+
+Execution of withdrawals is handled by the `execute_withdrawal` function, requiring parameters such as the unique identifier of the withdrawal and the event emitter used to emit events.
+
+### Swap Mechanism
+The module includes a `swap` function, used to swap tokens within the context of executing withdrawals, ensuring the internal state changes are correct before calling external callbacks.
+
+## Structures and Types
+
+### `Storage`
+This structure holds the interface to interact with the `DataStore` contract.
+- `strict_bank`: Represents the interface to interact with the `IStrictBankDispatcher`.
+
+### `Withdrawal`
+This structure represents a withdrawal within the system, holding essential information related to a specific withdrawal operation. The structure includes the following fields:
+- `key`: A unique identifier of the withdrawal, represented as a `felt252` type.
+- `account`: The account of the order, represented as a `ContractAddress`.
+- `receiver`: The receiver for any token transfers, represented as a `ContractAddress`.
+- `callback_contract`: The contract to call for callbacks, represented as a `ContractAddress`.
+- `ui_fee_receiver`: The UI fee receiver, represented as a `ContractAddress`.
+- `market`: The trading market, represented as a `ContractAddress`.
+- `long_token_swap_path`: An array of market addresses to swap through for long tokens, represented as a `Span32`.
+- `short_token_swap_path`: An array of market addresses to swap through for short tokens, represented as a `Span32`.
+- `market_token_amount`: The amount of market tokens that will be withdrawn, represented as a `u128` type.
+- `min_long_token_amount`: The minimum amount of long tokens that must be withdrawn, represented as a `u128` type.
+- `min_short_token_amount`: The minimum amount of short tokens that must be withdrawn, represented as a `u128` type.
+- `updated_at_block`: The block at which the withdrawal was last updated, represented as a `u64` type.
+- `execution_fee`: The execution fee for the withdrawal, represented as a `u128` type.
+- `callback_gas_limit`: The gas limit for calling the callback contract, represented as a `u128` type.
+
+### `Balance`
+Represents the balance of an asset and includes the following fields:
+- `amount`: The total amount of the asset, represented as a `u128` type.
+- `locked`: The amount of the asset that is locked, represented as a `u128` type.
+
+### `Asset`
+This structure represents an asset within the system and includes the following fields:
+- `symbol`: The symbol of the asset, represented as a string.
+- `decimals`: The number of decimals the asset uses, represented as a `u8` type.
+- `total_supply`: The total supply of the asset, represented as a `u128` type.
+
+### Other Structures
+- `CreateWithdrawalParams`: Holds parameters needed for creating a withdrawal, such as the receiver and the market on which the withdrawal will be executed.
+- `ExecuteWithdrawalParams`: Holds parameters needed for executing a withdrawal, such as the data store where withdrawal data is stored and the unique identifier of the withdrawal to execute.
+- `ExecuteWithdrawalCache`: Utilized to cache the results temporarily when executing a withdrawal.
+- `ExecuteWithdrawalResult`: Represents the result of a withdrawal execution, holding details of the output token and its amount.
+- `SwapCache`: Holds data related to token swap operations, such as the swap path markets and the output token and its amount.
+
+## Functions
+
+### `initialize`
+This function is utilized to initialize the contract with the address of the strict bank contract.
+
+### `record_transfer_in`
+Records the transfer in operation and returns a `u128` type representing the recorded value.
+
+### `transfer_out`
+Executes the transfer out operation to the specified receiver with the defined amount.
+
+### `sync_token_balance`
+Synchronizes the token balance and returns a `u128` type representing the synchronized value.
+
+## Errors
+
+The module employs `WithdrawalError` to address errors inherent to withdrawal operations. Here are the defined errors:
+- `ALREADY_INITIALIZED`: Triggered if the contract has already been initialized, represented by the constant `'already_initialized'`.
+- `NOT_FOUND`: Triggered when a specified withdrawal is not found in the system, represented by the constant `'withdrawal not found'`.
+- `CANT_BE_ZERO`: Triggered when a withdrawal account is zero, represented by the constant `'withdrawal account cant be 0'`.
+- `EMPTY_WITHDRAWAL_AMOUNT`: Occurs when an attempt is made to withdraw an empty amount, represented by the constant `'empty withdrawal amount'`.
+- `EMPTY_WITHDRAWAL`: Occurs when a withdrawal is empty, represented by the constant `'empty withdrawal'`.
+
+Additionally, the module defines several panic functions to handle specific error scenarios with more context:
+- `INSUFFICIENT_FEE_TOKEN_AMOUNT(data_1: u128, data_2: u128)`: Triggered when there is an insufficient amount of fee tokens, providing additional context with `data_1` and `data_2`.
+- `INSUFFICIENT_MARKET_TOKENS(data_1: u128, data_2: u128)`: Triggered when there are insufficient market tokens available, providing additional context with `data_1` and `data_2`.
+- `INVALID_POOL_VALUE_FOR_WITHDRAWAL(data: u128)`: Triggered when an invalid pool value is provided for withdrawal, providing additional context with `data`.
+- `INVALID_WITHDRAWAL_KEY(data: felt252)`: Triggered when an invalid withdrawal key is provided, providing additional context with `data`.
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..b2607303
--- /dev/null
+++ b/package.json
@@ -0,0 +1,9 @@
+{
+ "dependencies": {
+ "@types/node": "^20.11.16",
+ "dotenv": "^16.4.1",
+ "starknet": "^6.6.6",
+ "ts-node": "^10.9.2",
+ "typescript": "^5.3.3"
+ }
+}
diff --git a/scripts/actions/createLongOrder.ts b/scripts/actions/createLongOrder.ts
new file mode 100644
index 00000000..5a8d0b17
--- /dev/null
+++ b/scripts/actions/createLongOrder.ts
@@ -0,0 +1,70 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const marketTokenAddress = "0x69cfad927e7e4ef53261ad9a4630631ff8404746720ce3c73368de8291c4c4d"
+ const eth: string = "0x376bbceb1a044263cba28211fdcaee4e234ebf0c012521e1b258684bbc44949"
+ const usdc: string = "0x42a9a03ceb10ca07d3f598a627c414fe218b1138a78e3da6ce1675680cf95f2"
+
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+
+ const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, process.env.ORDER_HANDLER as string, provider);
+ const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+
+ const ethContract = new Contract(compiledERC20Sierra.abi, eth as string, provider)
+ ethContract.connect(account0)
+ const transferCall = ethContract.populate("transfer", [process.env.ORDER_VAULT as string, uint256.bnToUint256(1000000000000000000n)])
+ const transferTx = await ethContract.transfer(transferCall.calldata)
+ await provider.waitForTransaction(transferTx.transaction_hash)
+
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ roleStoreContract.connect(account0);
+
+ const roleCall4 = roleStoreContract.populate("grant_role", [process.env.ORDER_UTILS as string, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx4 = await roleStoreContract.grant_role(roleCall4.calldata)
+ await provider.waitForTransaction(grant_role_tx4.transaction_hash)
+
+ orderHandlerContract.connect(account0)
+ const createOrderParams = {
+ receiver: account0.address,
+ callback_contract: 0,
+ ui_fee_receiver: 0,
+ market: marketTokenAddress,
+ initial_collateral_token: eth,
+ swap_path: [],
+ size_delta_usd: uint256.bnToUint256(10000000000000000000000n),
+ initial_collateral_delta_amount: uint256.bnToUint256(2000000000000000000n),
+ trigger_price: uint256.bnToUint256(5000),
+ acceptable_price: uint256.bnToUint256(5500),
+ execution_fee: uint256.bnToUint256(0),
+ callback_gas_limit: uint256.bnToUint256(0),
+ min_output_amount: uint256.bnToUint256(0),
+ order_type: new CairoCustomEnum({ MarketIncrease: {} }),
+ decrease_position_swap_type: new CairoCustomEnum({ NoSwap: {} }),
+ is_long: 1,
+ referral_code: 0
+ };
+ const createOrderCall = orderHandlerContract.populate("create_order", [
+ account0.address,
+ createOrderParams
+ ])
+ const createOrderTx = await orderHandlerContract.create_order(createOrderCall.calldata)
+ await provider.waitForTransaction(createOrderTx.transaction_hash)
+ console.log("Order created.")
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/createMarket.ts b/scripts/actions/createMarket.ts
new file mode 100644
index 00000000..869b6820
--- /dev/null
+++ b/scripts/actions/createMarket.ts
@@ -0,0 +1,153 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ let eth = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
+
+ const dataStoreAddress = process.env.DATA_STORE as string
+ const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ const dataStoreContract = new Contract(compiledDataStoreSierra.abi, dataStoreAddress, provider)
+ dataStoreContract.connect(account0);
+ const dataCall = dataStoreContract.populate(
+ "set_address",
+ [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("FEE_TOKEN"))]), process.env.FEE_TOKEN as string])
+ const setAddressTx = await dataStoreContract.set_address(dataCall.calldata)
+ await provider.waitForTransaction(setAddressTx.transaction_hash)
+ const dataCall2 = dataStoreContract.populate(
+ "set_u256",
+ [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("MAX_SWAP_PATH_LENGTH"))]), 5n])
+ const setAddressTx2 = await dataStoreContract.set_u256(dataCall2.calldata)
+ await provider.waitForTransaction(setAddressTx2.transaction_hash)
+
+ const dataCall3 = dataStoreContract.populate(
+ "set_u256",
+ [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("MAX_ORACLE_PRICE_AGE"))]), 1000000000000n])
+ const setAddressTx3 = await dataStoreContract.set_u256(dataCall3.calldata)
+ await provider.waitForTransaction(setAddressTx2.transaction_hash)
+
+
+ console.log("Deploying USDC...")
+ const compiledERC20Casm = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.compiled_contract_class.json").toString( "ascii"))
+ const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+ const erc20CallData: CallData = new CallData(compiledERC20Sierra.abi)
+ const erc20Constructor: Calldata = erc20CallData.compile("constructor", {
+ name: "USDC",
+ symbol: "USDC",
+ initial_supply: "100000000000000000000000",
+ recipient: account0Address
+ })
+ const deployERC20Response = await account0.declareAndDeploy({
+ contract: compiledERC20Sierra,
+ casm: compiledERC20Casm,
+ constructorCalldata: erc20Constructor,
+ })
+ console.log("USDC Deployed at: " + deployERC20Response.deploy.contract_address)
+
+ const marketFactoryAddress = process.env.MARKET_FACTORY as string
+ const compiledMarketFactorySierra = json.parse(fs.readFileSync( "./target/dev/satoru_MarketFactory.contract_class.json").toString( "ascii"))
+
+ const roleStoreAddress = process.env.ROLE_STORE as string
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, roleStoreAddress, provider)
+ roleStoreContract.connect(account0)
+ const roleCall = roleStoreContract.populate("grant_role", [marketFactoryAddress, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx = await roleStoreContract.grant_role(roleCall.calldata)
+ await provider.waitForTransaction(grant_role_tx.transaction_hash)
+
+
+ const abi = compiledMarketFactorySierra.abi
+ const marketFactoryContract = new Contract(abi, marketFactoryAddress, provider);
+ console.log("Connected to MarketFactory: " + marketFactoryAddress)
+ marketFactoryContract.connect(account0)
+
+ console.log("Granting roles...")
+ const roleCall2 = roleStoreContract.populate("grant_role", [process.env.MARKET_FACTORY as string, shortString.encodeShortString("MARKET_KEEPER")])
+
+ const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+ console.log("Roles granted.")
+
+ console.log("Creating Market...")
+ const myCall = marketFactoryContract.populate("create_market", [
+ eth,
+ eth,
+ deployERC20Response.deploy.contract_address,
+ "market_type"
+ ]);
+ const res = await marketFactoryContract.create_market(myCall.calldata);
+ const marketTokenAddress = (await provider.waitForTransaction(res.transaction_hash) as any).events[0].data[1];
+ console.log("Market created: " + marketTokenAddress)
+
+ const orderVaultAddress = process.env.ORDER_VAULT as string
+ const ethContract = new Contract(compiledERC20Sierra.abi, eth as string, provider)
+ ethContract.connect(account0)
+ const transferCall = ethContract.populate("transfer", [orderVaultAddress, uint256.bnToUint256(1000n)])
+ const transferTx = await ethContract.transfer(transferCall.calldata)
+ await provider.waitForTransaction(transferTx.transaction_hash)
+ const transferCall2 = ethContract.populate("transfer", [marketTokenAddress, uint256.bnToUint256(10000n)])
+ const transferTx2 = await ethContract.transfer(transferCall2.calldata)
+ await provider.waitForTransaction(transferTx2.transaction_hash)
+
+ const usdcContract = new Contract(compiledERC20Sierra.abi, deployERC20Response.deploy.contract_address, provider)
+ usdcContract.connect(account0)
+ const transferUSDCCall = usdcContract.populate("transfer", [marketTokenAddress, uint256.bnToUint256(10000n)])
+ const transferUSDCTx = await usdcContract.transfer(transferUSDCCall.calldata)
+ await provider.waitForTransaction(transferUSDCTx.transaction_hash)
+
+ const compiledOracleSierra = json.parse(fs.readFileSync( "./target/dev/satoru_Oracle.contract_class.json").toString( "ascii"))
+
+ const abiOracle = compiledOracleSierra.abi
+ const oracleContract = new Contract(abiOracle, process.env.ORACLE as string, provider);
+ oracleContract.connect(account0);
+ const setPrimaryPriceCall1 = oracleContract.populate("set_primary_price", [ethContract.address, uint256.bnToUint256(5000n)])
+ const setPrimaryPriceTx1 = await oracleContract.set_primary_price(setPrimaryPriceCall1.calldata);
+ await provider.waitForTransaction(setPrimaryPriceTx1.transaction_hash)
+
+ const setPrimaryPriceCall2 = oracleContract.populate("set_primary_price", [usdcContract.address, uint256.bnToUint256(1n)])
+ const setPrimaryPriceTx2 = await oracleContract.set_primary_price(setPrimaryPriceCall2.calldata);
+ await provider.waitForTransaction(setPrimaryPriceTx2.transaction_hash)
+ console.log("Primary prices set.")
+ // const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, orderHandlerAddress, provider);
+
+ // orderHandlerContract.connect(account0)
+ // const createOrderParams = {
+ // receiver: account0.address,
+ // callback_contract: 0,
+ // ui_fee_receiver: 0,
+ // market: 0,
+ // initial_collateral_token: eth,
+ // swap_path: [marketTokenAddress],
+ // size_delta_usd: uint256.bnToUint256(1000),
+ // initial_collateral_delta_amount: uint256.bnToUint256(10000),
+ // trigger_price: uint256.bnToUint256(0),
+ // acceptable_price: uint256.bnToUint256(0),
+ // execution_fee: uint256.bnToUint256(0),
+ // callback_gas_limit: uint256.bnToUint256(0),
+ // min_output_amount: uint256.bnToUint256(0),
+ // order_type: new CairoCustomEnum({ MarketSwap: {} }),
+ // decrease_position_swap_type: new CairoCustomEnum({ NoSwap: {} }),
+ // is_long: 0,
+ // referral_code: 0
+ // };
+ // const createOrderCall = orderHandlerContract.populate("create_order", [
+ // account0.address,
+ // createOrderParams
+ // ])
+ // const createOrderTx = await orderHandlerContract.create_order(createOrderCall.calldata)
+ // await provider.waitForTransaction(createOrderTx.transaction_hash)
+ // console.log("Order created.")
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/createMarketAndDeposit.ts b/scripts/actions/createMarketAndDeposit.ts
new file mode 100644
index 00000000..5147fe2f
--- /dev/null
+++ b/scripts/actions/createMarketAndDeposit.ts
@@ -0,0 +1,371 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ // let eth = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
+
+ // const dataStoreAddress = process.env.DATA_STORE as string
+ // const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ // const dataStoreContract = new Contract(compiledDataStoreSierra.abi, dataStoreAddress, provider)
+ // dataStoreContract.connect(account0);
+ // const dataCall = dataStoreContract.populate(
+ // "set_address",
+ // [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("FEE_TOKEN"))]), process.env.FEE_TOKEN as string])
+ // const setAddressTx = await dataStoreContract.set_address(dataCall.calldata)
+ // await provider.waitForTransaction(setAddressTx.transaction_hash)
+ // const dataCall2 = dataStoreContract.populate(
+ // "set_u256",
+ // [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("MAX_SWAP_PATH_LENGTH"))]), 5n])
+ // const setAddressTx2 = await dataStoreContract.set_u256(dataCall2.calldata)
+ // await provider.waitForTransaction(setAddressTx2.transaction_hash)
+
+ // const dataCall3 = dataStoreContract.populate(
+ // "set_u256",
+ // [ec.starkCurve.poseidonHashMany([BigInt(shortString.encodeShortString("MAX_ORACLE_PRICE_AGE"))]), 1000000000000n])
+ // const setAddressTx3 = await dataStoreContract.set_u256(dataCall3.calldata)
+ // await provider.waitForTransaction(setAddressTx3.transaction_hash)
+
+ // const compiledERC20Casm = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.compiled_contract_class.json").toString( "ascii"))
+ // const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+ // const erc20CallData: CallData = new CallData(compiledERC20Sierra.abi)
+ // const erc20Constructor: Calldata = erc20CallData.compile("constructor", {
+ // name: "USDC",
+ // symbol: "USDC",
+ // initial_supply: "10000000000000000000",
+ // recipient: account0Address
+ // })
+ // const deployERC20Response = await account0.declareAndDeploy({
+ // contract: compiledERC20Sierra,
+ // casm: compiledERC20Casm,
+ // constructorCalldata: erc20Constructor,
+ // })
+ // console.log("USDC Deployed at: " + deployERC20Response.deploy.contract_address)
+
+ // const zETHCallData: CallData = new CallData(compiledERC20Sierra.abi)
+ // const zETHConstructor: Calldata = zETHCallData.compile("constructor", {
+ // name: "zEthereum",
+ // symbol: "zETH",
+ // initial_supply: "50000000000000000000000",
+ // recipient: account0Address
+ // })
+ // const deployzETHResponse = await account0.declareAndDeploy({
+ // contract: compiledERC20Sierra,
+ // casm: compiledERC20Casm,
+ // constructorCalldata: zETHConstructor,
+ // })
+ // console.log("zETH Deployed at: " + deployzETHResponse.deploy.contract_address)
+
+ // const marketFactoryAddress = process.env.MARKET_FACTORY as string
+ // const compiledMarketFactorySierra = json.parse(fs.readFileSync( "./target/dev/satoru_MarketFactory.contract_class.json").toString( "ascii"))
+
+ const roleStoreAddress = process.env.ROLE_STORE as string
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, roleStoreAddress, provider)
+ roleStoreContract.connect(account0)
+ const roleCall = roleStoreContract.populate("grant_role", ["0x04219D87E41d0eA40746f05DaB73659f5176cD328C5bE466027f93305089E166", shortString.encodeShortString("FROZEN_ORDER_KEEPER")])
+ const grant_role_tx = await roleStoreContract.grant_role(roleCall.calldata)
+ await provider.waitForTransaction(grant_role_tx.transaction_hash)
+
+
+ // const abi = compiledMarketFactorySierra.abi
+ // const marketFactoryContract = new Contract(abi, marketFactoryAddress, provider);
+ // console.log("Connected to MarketFactory: " + marketFactoryAddress)
+ // marketFactoryContract.connect(account0)
+
+ // console.log("Granting roles...")
+ // const roleCall2 = roleStoreContract.populate("grant_role", [process.env.MARKET_FACTORY as string, shortString.encodeShortString("MARKET_KEEPER")])
+ // const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ // await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+
+ // const roleCall3 = roleStoreContract.populate("grant_role", [process.env.DEPOSIT_HANDLER as string, shortString.encodeShortString("CONTROLLER")])
+ // const grant_role_tx3 = await roleStoreContract.grant_role(roleCall3.calldata)
+ // await provider.waitForTransaction(grant_role_tx3.transaction_hash)
+
+ // const roleCall4 = roleStoreContract.populate("grant_role", [process.env.ORDER_HANDLER as string, shortString.encodeShortString("CONTROLLER")])
+ // const grant_role_tx4 = await roleStoreContract.grant_role(roleCall4.calldata)
+ // await provider.waitForTransaction(grant_role_tx4.transaction_hash)
+ // console.log("Roles granted.")
+
+ // console.log("Creating Market...")
+ // const myCall = marketFactoryContract.populate("create_market", [
+ // deployzETHResponse.deploy.contract_address,
+ // deployzETHResponse.deploy.contract_address,
+ // deployERC20Response.deploy.contract_address,
+ // "market_type"
+ // ]);
+ // const res = await marketFactoryContract.create_market(myCall.calldata);
+ // const marketTokenAddress = (await provider.waitForTransaction(res.transaction_hash) as any).events[0].data[1];
+ // console.log("Market created: " + marketTokenAddress)
+
+ // // Set constants for trade
+ // dataStoreContract.connect(account0);
+ // const dataCall5 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pool_amount_key(marketTokenAddress, deployzETHResponse.deploy.contract_address),
+ // 2500000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx5 = await dataStoreContract.set_u256(dataCall5.calldata)
+ // await provider.waitForTransaction(setAddressTx5.transaction_hash)
+
+ // const dataCall6 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pool_amount_key(marketTokenAddress, deployERC20Response.deploy.contract_address),
+ // 2500000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx6 = await dataStoreContract.set_u256(dataCall6.calldata)
+ // await provider.waitForTransaction(setAddressTx6.transaction_hash)
+
+ // // Set Constants for long
+ // const dataCall7 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pnl_factor_key(
+ // "0x4896bc14d7c67b49131baf26724d3f29032ddd7539a3a8d88324140ea2de9b4",
+ // marketTokenAddress,
+ // true
+ // ),
+ // 50000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx7 = await dataStoreContract.set_u256(dataCall7.calldata)
+ // await provider.waitForTransaction(setAddressTx7.transaction_hash)
+
+ // const dataCall9 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pnl_factor_key(
+ // "0x425655404757d831905ce0c7aeb290f47c630d959038f3d087a009ba1236dbe",
+ // marketTokenAddress,
+ // true
+ // ),
+ // 50000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx9 = await dataStoreContract.set_u256(dataCall9.calldata)
+ // await provider.waitForTransaction(setAddressTx9.transaction_hash)
+
+ // const dataCall10 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_reserve_factor_key(
+ // marketTokenAddress,
+ // true
+ // ),
+ // 1000000000000000000n
+ // ]
+ // )
+ // const setAddressTx10 = await dataStoreContract.set_u256(dataCall10.calldata)
+ // await provider.waitForTransaction(setAddressTx10.transaction_hash)
+
+ // const dataCall11 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_open_interest_reserve_factor_key(
+ // marketTokenAddress,
+ // true
+ // ),
+ // 1000000000000000000n
+ // ]
+ // )
+ // const setAddressTx11 = await dataStoreContract.set_u256(dataCall11.calldata)
+ // await provider.waitForTransaction(setAddressTx11.transaction_hash)
+
+ // const dataCall12 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_open_interest_key(
+ // marketTokenAddress,
+ // deployzETHResponse.deploy.contract_address,
+ // true
+ // ),
+ // 1n
+ // ]
+ // )
+ // const setAddressTx12 = await dataStoreContract.set_u256(dataCall12.calldata)
+ // await provider.waitForTransaction(setAddressTx12.transaction_hash)
+
+ // const dataCall8 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_open_interest_key(
+ // marketTokenAddress,
+ // true
+ // ),
+ // 1000000000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx8 = await dataStoreContract.set_u256(dataCall8.calldata)
+ // await provider.waitForTransaction(setAddressTx8.transaction_hash)
+
+ // // Set constants for short
+ // const dataCall13 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pnl_factor_key(
+ // "0x4896bc14d7c67b49131baf26724d3f29032ddd7539a3a8d88324140ea2de9b4",
+ // marketTokenAddress,
+ // false
+ // ),
+ // 50000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx13 = await dataStoreContract.set_u256(dataCall13.calldata)
+ // await provider.waitForTransaction(setAddressTx13.transaction_hash)
+
+ // const dataCall14 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_pnl_factor_key(
+ // "0x425655404757d831905ce0c7aeb290f47c630d959038f3d087a009ba1236dbe",
+ // marketTokenAddress,
+ // false
+ // ),
+ // 50000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx14 = await dataStoreContract.set_u256(dataCall14.calldata)
+ // await provider.waitForTransaction(setAddressTx14.transaction_hash)
+
+ // const dataCall15 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_reserve_factor_key(
+ // marketTokenAddress,
+ // false
+ // ),
+ // 1000000000000000000n
+ // ]
+ // )
+ // const setAddressTx15 = await dataStoreContract.set_u256(dataCall15.calldata)
+ // await provider.waitForTransaction(setAddressTx15.transaction_hash)
+
+ // const dataCall16 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_open_interest_reserve_factor_key(
+ // marketTokenAddress,
+ // false
+ // ),
+ // 1000000000000000000n
+ // ]
+ // )
+ // const setAddressTx16 = await dataStoreContract.set_u256(dataCall16.calldata)
+ // await provider.waitForTransaction(setAddressTx16.transaction_hash)
+
+ // const dataCall17 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_open_interest_key(
+ // marketTokenAddress,
+ // deployERC20Response.deploy.contract_address,
+ // false
+ // ),
+ // 1n
+ // ]
+ // )
+ // const setAddressTx17 = await dataStoreContract.set_u256(dataCall17.calldata)
+ // await provider.waitForTransaction(setAddressTx17.transaction_hash)
+
+ // const dataCall18 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_open_interest_key(
+ // marketTokenAddress,
+ // false
+ // ),
+ // 1000000000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx18 = await dataStoreContract.set_u256(dataCall18.calldata)
+ // await provider.waitForTransaction(setAddressTx18.transaction_hash)
+
+
+ // const usdcContract = new Contract(compiledERC20Sierra.abi, deployERC20Response.deploy.contract_address, provider)
+ // usdcContract.connect(account0)
+
+ // const depositVaultAddress = process.env.DEPOSIT_VAULT as string
+ // const zEthContract = new Contract(compiledERC20Sierra.abi, deployzETHResponse.deploy.contract_address, provider)
+ // zEthContract.connect(account0)
+
+ // const transferCall2 = zEthContract.populate("mint", [marketTokenAddress, uint256.bnToUint256(50000000000000000000000000000000000000n)])
+ // const transferTx2 = await zEthContract.mint(transferCall2.calldata)
+ // await provider.waitForTransaction(transferTx2.transaction_hash)
+ // const transferUSDCCall = usdcContract.populate("mint", [marketTokenAddress, uint256.bnToUint256(25000000000000000000000000000000000000000n)])
+ // const transferUSDCTx = await usdcContract.mint(transferUSDCCall.calldata)
+ // await provider.waitForTransaction(transferUSDCTx.transaction_hash)
+
+ // console.log("All pre-settings done.")
+
+ // NOT NEEDED NOW
+
+ // const compiledERC20Casm = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.compiled_contract_class.json").toString( "ascii"))
+ // const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+ // const erc20CallData: CallData = new CallData(compiledERC20Sierra.abi)
+
+ // let USDCAddress = "0x6f82b80bfead3a249ee4352b27075dfa327de91e8e6df9755eb4f31de406d98";
+ // let ETHaddress = "0x369c220f2a4699495bfe73ffe8a522f1bf1570c903c0d8fcf3767a252f7ae9a";
+ // let MarketTokenAddress = "0x122cd6989d2429f580a0bff5e70cdb84b2bff4f8d19cee6b30a15d08c447e85";
+
+ // const usdcContract = new Contract(compiledERC20Sierra.abi, USDCAddress, provider)
+ // usdcContract.connect(account0)
+
+ // const zEthContract = new Contract(compiledERC20Sierra.abi, ETHaddress, provider)
+ // zEthContract.connect(account0)
+
+ // let depositVaultAddress = "0xad087c985ff7655d26eeaa496510a0590dd73b23d7e15beb53c79045ee4b6b";
+ // let depositHandlerAddress = "0x7d82433606ef19a1f8a2d7e9be45c02677e214b83d2a079c930bc379ee246ef";
+
+ // const transferCall = zEthContract.populate("mint", [depositVaultAddress, uint256.bnToUint256(50000000000000000000000000000n)])
+ // const transferTx = await zEthContract.mint(transferCall.calldata)
+ // await provider.waitForTransaction(transferTx.transaction_hash)
+ // const transferUSDCCall2 = usdcContract.populate("mint", [depositVaultAddress, uint256.bnToUint256(50000000000000000000000000000n)])
+ // const transferUSDCTx2 = await usdcContract.mint(transferUSDCCall2.calldata)
+ // await provider.waitForTransaction(transferUSDCTx2.transaction_hash)
+
+ // console.log("Sending tokens to the deposit vault...")
+
+ // console.log("Creating Deposit...")
+ // const compiledDepositHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DepositHandler.contract_class.json").toString( "ascii"))
+
+ // const depositHandlerContract = new Contract(compiledDepositHandlerSierra.abi, depositHandlerAddress, provider);
+
+ // depositHandlerContract.connect(account0)
+ // const createDepositParams = {
+ // receiver: account0.address,
+ // callback_contract: 0,
+ // ui_fee_receiver: 0,
+ // market: MarketTokenAddress,
+ // initial_long_token: ETHaddress,
+ // initial_short_token: USDCAddress,
+ // long_token_swap_path: [],
+ // short_token_swap_path: [],
+ // min_market_tokens: uint256.bnToUint256(0),
+ // execution_fee: uint256.bnToUint256(0),
+ // callback_gas_limit: uint256.bnToUint256(0),
+ // };
+ // const createOrderCall = depositHandlerContract.populate("create_deposit", [
+ // account0.address,
+ // createDepositParams
+ // ])
+ // const createOrderTx = await depositHandlerContract.create_deposit(createOrderCall.calldata)
+ // await provider.waitForTransaction(createOrderTx.transaction_hash)
+ // console.log("Deposit created.")
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/createSwapOrder.ts b/scripts/actions/createSwapOrder.ts
new file mode 100644
index 00000000..3164f3b6
--- /dev/null
+++ b/scripts/actions/createSwapOrder.ts
@@ -0,0 +1,72 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const marketTokenAddress = "0x4b3bd2fe7f3dd02a6a143a3040ede80048388e0cf1c20dc748d6a6d6fa93069"
+ const eth: string = "0x75acffcc1c3661fe1cfbb6d2c444355ef01e85a40e65962a4d9a2ac38903934"
+ const usdc: string = "0x70d22d4962de09d9ec0a590e9ff33a496425277235890575457f9582d837964"
+
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+
+ const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, process.env.ORDER_HANDLER as string, provider);
+ const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+
+ const ethContract = new Contract(compiledERC20Sierra.abi, eth as string, provider)
+ ethContract.connect(account0)
+ const transferCall = ethContract.populate("transfer", [process.env.ORDER_VAULT as string, uint256.bnToUint256(1000000000000000000n)])
+ const transferTx = await ethContract.transfer(transferCall.calldata)
+ await provider.waitForTransaction(transferTx.transaction_hash)
+
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ roleStoreContract.connect(account0);
+
+ console.log("Granting roles...")
+ const roleCall2 = roleStoreContract.populate("grant_role", ["0x05fc5a52d7141a90b79663eb22b80f7a13ec1fce7232bc8c4a03528f552cb02b" as string, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+ console.log("Roles granted.")
+
+ orderHandlerContract.connect(account0)
+ const createOrderParams = {
+ receiver: account0.address,
+ callback_contract: 0,
+ ui_fee_receiver: 0,
+ market: 0,
+ initial_collateral_token: eth,
+ swap_path: [marketTokenAddress],
+ size_delta_usd: uint256.bnToUint256(5000000000000000000000n),
+ initial_collateral_delta_amount: uint256.bnToUint256(1000000000000000000n),
+ trigger_price: uint256.bnToUint256(0),
+ acceptable_price: uint256.bnToUint256(0),
+ execution_fee: uint256.bnToUint256(0),
+ callback_gas_limit: uint256.bnToUint256(0),
+ min_output_amount: uint256.bnToUint256(0),
+ order_type: new CairoCustomEnum({ MarketSwap: {} }),
+ decrease_position_swap_type: new CairoCustomEnum({ NoSwap: {} }),
+ is_long: 0,
+ referral_code: 0
+ };
+ const createOrderCall = orderHandlerContract.populate("create_order", [
+ account0.address,
+ createOrderParams
+ ])
+ const createOrderTx = await orderHandlerContract.create_order(createOrderCall.calldata)
+ await provider.waitForTransaction(createOrderTx.transaction_hash)
+ console.log("Order created.")
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/executeDeposit.ts b/scripts/actions/executeDeposit.ts
new file mode 100644
index 00000000..6c9bfe10
--- /dev/null
+++ b/scripts/actions/executeDeposit.ts
@@ -0,0 +1,79 @@
+import { Account, hash, Contract, json, Calldata, CallData, RpcProvider, shortString, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function deploy() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ // const marketToken = "0x122cd6989d2429f580a0bff5e70cdb84b2bff4f8d19cee6b30a15d08c447e85"
+ // const eth = "0x369c220f2a4699495bfe73ffe8a522f1bf1570c903c0d8fcf3767a252f7ae9a"
+ // const usdc = "0x6f82b80bfead3a249ee4352b27075dfa327de91e8e6df9755eb4f31de406d98"
+ console.log("Deploying with Account: " + account0Address)
+ console.log("RPC: " + providerUrl)
+
+ const depositHandlerAddress = "0x7d82433606ef19a1f8a2d7e9be45c02677e214b83d2a079c930bc379ee246ef";
+ // const dataStoreAddress = "0x12b79d662e668a585b978c8fa80c33c269297ee14eba2383829ef1890a6e201";
+ const compiledDepositHandlerSierra = json.parse(fs.readFileSync("./target/dev/satoru_DepositHandler.contract_class.json").toString( "ascii"))
+
+ // const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ // const dataStoreContract = new Contract(compiledDataStoreSierra.abi, dataStoreAddress, provider)
+ // dataStoreContract.connect(account0);
+
+ // dataStoreContract.connect(account0);
+ // const dataCall5 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_pool_amount_key(marketToken, eth),
+ // 50000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx5 = await dataStoreContract.set_u256(dataCall5.calldata)
+ // await provider.waitForTransaction(setAddressTx5.transaction_hash)
+
+ // const dataCall6 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_pool_amount_key(marketToken, usdc),
+ // 50000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx6 = await dataStoreContract.set_u256(dataCall6.calldata)
+ // await provider.waitForTransaction(setAddressTx6.transaction_hash)
+
+ const depositHandlerContract = new Contract(compiledDepositHandlerSierra.abi, depositHandlerAddress, provider);
+
+ const setPricesParams = {
+ signer_info: 1,
+ tokens: ["0x369c220f2a4699495bfe73ffe8a522f1bf1570c903c0d8fcf3767a252f7ae9a", "0x6f82b80bfead3a249ee4352b27075dfa327de91e8e6df9755eb4f31de406d98"],
+ compacted_min_oracle_block_numbers: [8189, 8189],
+ compacted_max_oracle_block_numbers: [81189, 81189],
+ compacted_oracle_timestamps: [171119803, 10],
+ compacted_decimals: [1, 1],
+ compacted_min_prices: [2147483648010000], // 500000, 10000 compacted
+ compacted_min_prices_indexes: [0],
+ compacted_max_prices: [3060, 1], // 500000, 10000 compacted
+ compacted_max_prices_indexes: [0],
+ signatures: [
+ ['signatures1', 'signatures2'], ['signatures1', 'signatures2']
+ ],
+ price_feed_tokens: []
+ };
+
+ depositHandlerContract.connect(account0)
+ let key = "0x4d65a6c15f989ebcccc12f7ad07d69e0d2e3caede2bd40de1f2eb5898c50c17";
+ const executeOrderCall = depositHandlerContract.populate("execute_deposit", [
+ key,
+ setPricesParams
+ ])
+ let tx = await depositHandlerContract.execute_deposit(executeOrderCall.calldata)
+
+}
+
+deploy()
\ No newline at end of file
diff --git a/scripts/actions/executeLongOrder.ts b/scripts/actions/executeLongOrder.ts
new file mode 100644
index 00000000..8e049b23
--- /dev/null
+++ b/scripts/actions/executeLongOrder.ts
@@ -0,0 +1,83 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const marketTokenAddress = "0x69cfad927e7e4ef53261ad9a4630631ff8404746720ce3c73368de8291c4c4d"
+ const eth: string = "0x376bbceb1a044263cba28211fdcaee4e234ebf0c012521e1b258684bbc44949"
+ const usdc: string = "0x42a9a03ceb10ca07d3f598a627c414fe218b1138a78e3da6ce1675680cf95f2"
+
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+
+ const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, process.env.ORDER_HANDLER as string, provider);
+
+
+ // const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ // const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ // roleStoreContract.connect(account0);
+
+ // console.log("Granting roles...")
+ // const roleCall2 = roleStoreContract.populate("grant_role", [account0Address as string, shortString.encodeShortString("ORDER_KEEPER")])
+ // const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ // await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+ // const roleCall3 = roleStoreContract.populate("grant_role", [process.env.INCREASE_ORDER_UTILS as string, shortString.encodeShortString("CONTROLLER")])
+ // const grant_role_tx3 = await roleStoreContract.grant_role(roleCall3.calldata)
+ // await provider.waitForTransaction(grant_role_tx3.transaction_hash)
+
+ // console.log("Roles granted.")
+
+ const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ const dataStoreContract = new Contract(compiledDataStoreSierra.abi, process.env.DATA_STORE as string, provider)
+ dataStoreContract.connect(account0)
+ const dataCall8 = dataStoreContract.populate(
+ "remove_position",
+ [
+ "0x5985ad845114a848d9cffdf9124a029e1d3fe1e704ed8230e42872f80f88cd1",
+ "0x4eaaccd6d2a2d9d1c0404cd2fea8485d62b437415948309736fdfd2542aee3"
+ ]
+ )
+ const setAddressTx8 = await dataStoreContract.remove_position(dataCall8.calldata)
+ await provider.waitForTransaction(setAddressTx8.transaction_hash)
+
+
+
+ // orderHandlerContract.connect(account0)
+ // const setPricesParams = {
+ // signer_info: 1,
+ // tokens: ["0x369c220f2a4699495bfe73ffe8a522f1bf1570c903c0d8fcf3767a252f7ae9a", "0x6f82b80bfead3a249ee4352b27075dfa327de91e8e6df9755eb4f31de406d98"],
+ // compacted_min_oracle_block_numbers: [63970, 63970],
+ // compacted_max_oracle_block_numbers: [64901, 64901],
+ // compacted_oracle_timestamps: [171119803, 10],
+ // compacted_decimals: [1, 1],
+ // compacted_min_prices: [2147483648010000], // 500000, 10000 compacted
+ // compacted_min_prices_indexes: [0],
+ // compacted_max_prices: [3389, 1], // 500000, 10000 compacted
+ // compacted_max_prices_indexes: [0],
+ // signatures: [
+ // ['signatures1', 'signatures2'], ['signatures1', 'signatures2']
+ // ],
+ // price_feed_tokens: []
+ // };
+
+ // orderHandlerContract.connect(account0)
+ // let key = "0x1ecd2ae448fe9c2d0b632699a4c89f250f765d08dbba45a1a79c97ebd4dd155";
+ // const executeOrderCall = orderHandlerContract.populate("execute_order", [
+ // key,
+ // setPricesParams,
+ // ])
+ // let tx = await orderHandlerContract.execute_order(executeOrderCall.calldata)
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/executeSwapOrder.ts b/scripts/actions/executeSwapOrder.ts
new file mode 100644
index 00000000..70caf1fd
--- /dev/null
+++ b/scripts/actions/executeSwapOrder.ts
@@ -0,0 +1,70 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const marketTokenAddress = "0x4b3bd2fe7f3dd02a6a143a3040ede80048388e0cf1c20dc748d6a6d6fa93069"
+ const eth: string = "0x75acffcc1c3661fe1cfbb6d2c444355ef01e85a40e65962a4d9a2ac38903934"
+ const usdc: string = "0x70d22d4962de09d9ec0a590e9ff33a496425277235890575457f9582d837964"
+
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+
+ const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, process.env.ORDER_HANDLER as string, provider);
+
+
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ roleStoreContract.connect(account0);
+
+ console.log("Granting roles...")
+ const roleCall2 = roleStoreContract.populate("grant_role", [account0Address as string, shortString.encodeShortString("ORDER_KEEPER")])
+ const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+ const roleCall3 = roleStoreContract.populate("grant_role", ["0x04b79329e9b295a50a27533d52484e0e3eb36a7f3303274745b6fe0e5dce7cc3" as string, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx3 = await roleStoreContract.grant_role(roleCall3.calldata)
+ await provider.waitForTransaction(grant_role_tx3.transaction_hash)
+
+ console.log("Roles granted.")
+
+
+ orderHandlerContract.connect(account0)
+ const setPricesParams = {
+ signer_info: 1,
+ tokens: ["0x4b76dd1e0a8d0bc196aa75d7a85a6cc81cf7bc8e0cd2e5061237477eb2c109a", "0x6b6f734dca33adeb315c1ff399886b577bc3f2b51165af9277ca0096847d267"],
+ compacted_min_oracle_block_numbers: [63970, 63970],
+ compacted_max_oracle_block_numbers: [64901, 64901],
+ compacted_oracle_timestamps: [171119803, 10],
+ compacted_decimals: [1, 1],
+ compacted_min_prices: [2147483648010000], // 500000, 10000 compacted
+ compacted_min_prices_indexes: [0],
+ compacted_max_prices: [2147483648010000], // 500000, 10000 compacted
+ compacted_max_prices_indexes: [0],
+ signatures: [
+ ['signatures1', 'signatures2'], ['signatures1', 'signatures2']
+ ],
+ price_feed_tokens: []
+ };
+
+ orderHandlerContract.connect(account0)
+ let key = "0x5dabb2c7c283c2b4759e3e8e38131a9f825decf26bd73a2e720c02222fa3c2f";
+ const executeOrderCall = orderHandlerContract.populate("execute_order_keeper", [
+ key,
+ setPricesParams,
+ account0Address
+ ])
+ let tx = await orderHandlerContract.execute_order_keeper(executeOrderCall.calldata)
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/actions/openAndCloseLong.ts b/scripts/actions/openAndCloseLong.ts
new file mode 100644
index 00000000..5a8d0b17
--- /dev/null
+++ b/scripts/actions/openAndCloseLong.ts
@@ -0,0 +1,70 @@
+import { Account, Contract, json, Calldata, CallData, RpcProvider, shortString, uint256, CairoCustomEnum, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function create_market() {
+
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const marketTokenAddress = "0x69cfad927e7e4ef53261ad9a4630631ff8404746720ce3c73368de8291c4c4d"
+ const eth: string = "0x376bbceb1a044263cba28211fdcaee4e234ebf0c012521e1b258684bbc44949"
+ const usdc: string = "0x42a9a03ceb10ca07d3f598a627c414fe218b1138a78e3da6ce1675680cf95f2"
+
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Interacting with Account: " + account0Address)
+
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+
+ const orderHandlerContract = new Contract(compiledOrderHandlerSierra.abi, process.env.ORDER_HANDLER as string, provider);
+ const compiledERC20Sierra = json.parse(fs.readFileSync( "./target/dev/satoru_ERC20.contract_class.json").toString( "ascii"))
+
+ const ethContract = new Contract(compiledERC20Sierra.abi, eth as string, provider)
+ ethContract.connect(account0)
+ const transferCall = ethContract.populate("transfer", [process.env.ORDER_VAULT as string, uint256.bnToUint256(1000000000000000000n)])
+ const transferTx = await ethContract.transfer(transferCall.calldata)
+ await provider.waitForTransaction(transferTx.transaction_hash)
+
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ roleStoreContract.connect(account0);
+
+ const roleCall4 = roleStoreContract.populate("grant_role", [process.env.ORDER_UTILS as string, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx4 = await roleStoreContract.grant_role(roleCall4.calldata)
+ await provider.waitForTransaction(grant_role_tx4.transaction_hash)
+
+ orderHandlerContract.connect(account0)
+ const createOrderParams = {
+ receiver: account0.address,
+ callback_contract: 0,
+ ui_fee_receiver: 0,
+ market: marketTokenAddress,
+ initial_collateral_token: eth,
+ swap_path: [],
+ size_delta_usd: uint256.bnToUint256(10000000000000000000000n),
+ initial_collateral_delta_amount: uint256.bnToUint256(2000000000000000000n),
+ trigger_price: uint256.bnToUint256(5000),
+ acceptable_price: uint256.bnToUint256(5500),
+ execution_fee: uint256.bnToUint256(0),
+ callback_gas_limit: uint256.bnToUint256(0),
+ min_output_amount: uint256.bnToUint256(0),
+ order_type: new CairoCustomEnum({ MarketIncrease: {} }),
+ decrease_position_swap_type: new CairoCustomEnum({ NoSwap: {} }),
+ is_long: 1,
+ referral_code: 0
+ };
+ const createOrderCall = orderHandlerContract.populate("create_order", [
+ account0.address,
+ createOrderParams
+ ])
+ const createOrderTx = await orderHandlerContract.create_order(createOrderCall.calldata)
+ await provider.waitForTransaction(createOrderTx.transaction_hash)
+ console.log("Order created.")
+}
+
+create_market()
\ No newline at end of file
diff --git a/scripts/app/deployApp.ts b/scripts/app/deployApp.ts
new file mode 100644
index 00000000..dc360cc5
--- /dev/null
+++ b/scripts/app/deployApp.ts
@@ -0,0 +1,409 @@
+import { Account, hash, Contract, json, Calldata, CallData, RpcProvider, shortString } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function deploy() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Deploying with Account: " + account0Address)
+ const resp = await provider.getSpecVersion();
+ console.log('rpc version =', resp);
+ const compiledRoleStoreCasm = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.compiled_contract_class.json").toString( "ascii"))
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreCallData: CallData = new CallData(compiledRoleStoreSierra.abi)
+ const roleStoreConstructor: Calldata = roleStoreCallData.compile("constructor", { admin: account0.address })
+ const deployRoleStoreResponse = await account0.declareAndDeploy({
+ contract: compiledRoleStoreSierra,
+ casm: compiledRoleStoreCasm,
+ constructorCalldata: roleStoreConstructor
+ })
+ console.log("RoleStore Deployed: " + deployRoleStoreResponse.deploy.contract_address)
+
+ const compiledDataStoreCasm = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.compiled_contract_class.json").toString( "ascii"))
+ const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ const dataStoreCallData: CallData = new CallData(compiledDataStoreSierra.abi)
+ const dataStoreConstructor: Calldata = dataStoreCallData.compile("constructor", {
+ role_store_address: deployRoleStoreResponse.deploy.contract_address
+ })
+ const deployDataStoreResponse = await account0.declareAndDeploy({
+ contract: compiledDataStoreSierra,
+ casm: compiledDataStoreCasm ,
+ constructorCalldata: dataStoreConstructor,
+ })
+ console.log("DataStore Deployed: " + deployDataStoreResponse.deploy.contract_address)
+
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, deployRoleStoreResponse.deploy.contract_address, provider)
+ roleStoreContract.connect(account0);
+ const roleCall = roleStoreContract.populate("grant_role", [account0.address, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx = await roleStoreContract.grant_role(roleCall.calldata)
+ await provider.waitForTransaction(grant_role_tx.transaction_hash)
+ console.log("Controller role granted.")
+
+ console.log("Deploying EventEmitter...")
+ const compiledEventEmitterCasm = json.parse(fs.readFileSync( "./target/dev/satoru_EventEmitter.compiled_contract_class.json").toString( "ascii"))
+ const compiledEventEmitterSierra = json.parse(fs.readFileSync( "./target/dev/satoru_EventEmitter.contract_class.json").toString( "ascii"))
+ const eventEmitterCallData: CallData = new CallData(compiledEventEmitterSierra.abi)
+ const eventEmitterConstructor: Calldata = eventEmitterCallData.compile("constructor", {})
+ const deployEventEmitterResponse = await account0.declareAndDeploy({
+ contract: compiledEventEmitterSierra,
+ casm: compiledEventEmitterCasm ,
+ constructorCalldata: eventEmitterConstructor,
+ })
+ console.log("EventEmitter Deployed: " + deployEventEmitterResponse.deploy.contract_address)
+
+ const compiledOracleStoreCasm = json.parse(fs.readFileSync( "./target/dev/satoru_OracleStore.compiled_contract_class.json").toString( "ascii"))
+ const compiledOracleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OracleStore.contract_class.json").toString( "ascii"))
+ const oracleStoreCallData: CallData = new CallData(compiledOracleStoreSierra.abi)
+ const oracleStoreConstructor: Calldata = oracleStoreCallData.compile("constructor", {
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address
+ })
+ const deployOracleStoreResponse = await account0.declareAndDeploy({
+ contract: compiledOracleStoreSierra,
+ casm: compiledOracleStoreCasm ,
+ constructorCalldata: oracleStoreConstructor,
+ })
+ console.log("OracleStore Deployed: " + deployOracleStoreResponse.deploy.contract_address)
+
+ const compiledOracleCasm = json.parse(fs.readFileSync( "./target/dev/satoru_Oracle.compiled_contract_class.json").toString( "ascii"))
+ const compiledOracleSierra = json.parse(fs.readFileSync( "./target/dev/satoru_Oracle.contract_class.json").toString( "ascii"))
+ const oracleCallData: CallData = new CallData(compiledOracleSierra.abi)
+ const oracleConstructor: Calldata = oracleCallData.compile("constructor", {
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ oracle_store_address: deployOracleStoreResponse.deploy.contract_address,
+ pragma_address: account0.address
+ })
+ const deployOracleResponse = await account0.declareAndDeploy({
+ contract: compiledOracleSierra,
+ casm: compiledOracleCasm ,
+ constructorCalldata: oracleConstructor,
+ })
+ console.log("Oracle Deployed: " + deployOracleResponse.deploy.contract_address)
+
+ const compiledOrderVaultCasm = json.parse(fs.readFileSync( "./target/dev/satoru_OrderVault.compiled_contract_class.json").toString( "ascii"))
+ const compiledOrderVaultSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderVault.contract_class.json").toString( "ascii"))
+ const orderVaultCallData: CallData = new CallData(compiledOrderVaultSierra.abi)
+ const orderVaultConstructor: Calldata = orderVaultCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ })
+ const deployOrderVaultResponse = await account0.declareAndDeploy({
+ contract: compiledOrderVaultSierra,
+ casm: compiledOrderVaultCasm ,
+ constructorCalldata: orderVaultConstructor,
+ })
+ console.log("OrderVault Deployed: " + deployOrderVaultResponse.deploy.contract_address)
+
+ const compiledSwapHandlerCasm = json.parse(fs.readFileSync( "./target/dev/satoru_SwapHandler.compiled_contract_class.json").toString( "ascii"))
+ const compiledSwapHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_SwapHandler.contract_class.json").toString( "ascii"))
+ const swapHandlerCallData: CallData = new CallData(compiledSwapHandlerSierra.abi)
+ const swapHandlerConstructor: Calldata = swapHandlerCallData.compile("constructor", {
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ })
+ const deploySwapHandlerResponse = await account0.declareAndDeploy({
+ contract: compiledSwapHandlerSierra,
+ casm: compiledSwapHandlerCasm ,
+ constructorCalldata: swapHandlerConstructor,
+ })
+ console.log("SwapHandler Deployed: " + deploySwapHandlerResponse.deploy.contract_address)
+
+ const compiledReferralStorageCasm = json.parse(fs.readFileSync( "./target/dev/satoru_ReferralStorage.compiled_contract_class.json").toString( "ascii"))
+ const compiledReferralStorageSierra = json.parse(fs.readFileSync( "./target/dev/satoru_ReferralStorage.contract_class.json").toString( "ascii"))
+ const referralStorageCallData: CallData = new CallData(compiledReferralStorageSierra.abi)
+ const referralStorageConstructor: Calldata = referralStorageCallData.compile("constructor", {
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ })
+ const deployReferralStorageResponse = await account0.declareAndDeploy({
+ contract: compiledReferralStorageSierra,
+ casm: compiledReferralStorageCasm ,
+ constructorCalldata: referralStorageConstructor,
+ })
+ console.log("ReferralStorage Deployed: " + deployReferralStorageResponse.deploy.contract_address)
+
+ const compiledIncreaseOrderUtilsCasm = json.parse(fs.readFileSync( "./target/dev/satoru_IncreaseOrderUtils.compiled_contract_class.json").toString( "ascii"))
+ const compiledIncreaseOrderUtilsSierra = json.parse(fs.readFileSync( "./target/dev/satoru_IncreaseOrderUtils.contract_class.json").toString( "ascii"))
+ const increaseOrderUtilsCallData: CallData = new CallData(compiledIncreaseOrderUtilsSierra.abi)
+ const increaseOrderUtilsConstructor: Calldata = increaseOrderUtilsCallData.compile("constructor", {})
+ const deployIncreaseOrderUtilsResponse = await account0.declareAndDeploy({
+ contract: compiledIncreaseOrderUtilsSierra,
+ casm: compiledIncreaseOrderUtilsCasm,
+ })
+ console.log("IncreaseOrderUtils Deployed: " + deployIncreaseOrderUtilsResponse.deploy.contract_address)
+
+
+ const compiledDecreaseOrderUtilsCasm = json.parse(fs.readFileSync( "./target/dev/satoru_DecreaseOrderUtils.compiled_contract_class.json").toString( "ascii"))
+ const compiledDecreaseOrderUtilsSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DecreaseOrderUtils.contract_class.json").toString( "ascii"))
+ const decreaseOrderUtilsCallData: CallData = new CallData(compiledDecreaseOrderUtilsSierra.abi)
+ const decreaseOrderUtilsConstructor: Calldata = decreaseOrderUtilsCallData.compile("constructor", {})
+ const deployDecreaseOrderUtilsResponse = await account0.declareAndDeploy({
+ contract: compiledDecreaseOrderUtilsSierra,
+ casm: compiledDecreaseOrderUtilsCasm,
+ })
+ console.log("DecreaseOrderUtils Deployed: " + deployDecreaseOrderUtilsResponse.deploy.contract_address)
+
+ const compiledSwapOrderUtilsCasm = json.parse(fs.readFileSync( "./target/dev/satoru_SwapOrderUtils.compiled_contract_class.json").toString( "ascii"))
+ const compiledSwapOrderUtilsSierra = json.parse(fs.readFileSync( "./target/dev/satoru_SwapOrderUtils.contract_class.json").toString( "ascii"))
+ const swapOrderUtilsCallData: CallData = new CallData(compiledSwapOrderUtilsSierra.abi)
+ const swapOrderUtilsConstructor: Calldata = swapOrderUtilsCallData.compile("constructor", {})
+ const deploySwapOrderUtilsResponse = await account0.declareAndDeploy({
+ contract: compiledSwapOrderUtilsSierra,
+ casm: compiledSwapOrderUtilsCasm,
+ })
+ console.log("SwapOrderUtils Deployed: " + deploySwapOrderUtilsResponse.deploy.contract_address)
+
+ const compiledOrderUtilsCasm = json.parse(fs.readFileSync( "./target/dev/satoru_OrderUtils.compiled_contract_class.json").toString( "ascii"))
+ const compiledOrderUtilsSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderUtils.contract_class.json").toString( "ascii"))
+ const orderUtilsCallData: CallData = new CallData(compiledOrderUtilsSierra.abi)
+ const orderUtilsConstructor: Calldata = orderUtilsCallData.compile("constructor", {
+ increase_order_class_hash: deployIncreaseOrderUtilsResponse.deploy.classHash,
+ decrease_order_class_hash: deployDecreaseOrderUtilsResponse.deploy.classHash,
+ swap_order_class_hash: deploySwapOrderUtilsResponse.deploy.classHash
+ })
+ const deployOrderUtilsResponse = await account0.declareAndDeploy({
+ contract: compiledOrderUtilsSierra,
+ casm: compiledOrderUtilsCasm,
+ constructorCalldata: orderUtilsConstructor
+ })
+ console.log("OrderUtils Deployed: " + deployOrderUtilsResponse.deploy.contract_address)
+
+ const compiledOrderHandlerCasm = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.compiled_contract_class.json").toString( "ascii"))
+ const compiledOrderHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_OrderHandler.contract_class.json").toString( "ascii"))
+ const orderHandlerCallData: CallData = new CallData(compiledOrderHandlerSierra.abi)
+ const orderHandlerConstructor: Calldata = orderHandlerCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ order_vault_address: deployOrderVaultResponse.deploy.contract_address,
+ oracle_address: deployOracleResponse.deploy.contract_address,
+ swap_handler_address: deploySwapHandlerResponse.deploy.contract_address,
+ referral_storage_address: deployReferralStorageResponse.deploy.contract_address,
+ order_utils_class_hash: deployOrderUtilsResponse.deploy.classHash,
+ increase_order_utils_class_hash: deployIncreaseOrderUtilsResponse.deploy.classHash,
+ decrease_order_utils_class_hash: deployDecreaseOrderUtilsResponse.deploy.classHash,
+ swap_order_utils_class_hash: deploySwapOrderUtilsResponse.deploy.classHash,
+ })
+ const deployOrderHandlerResponse = await account0.declareAndDeploy({
+ contract: compiledOrderHandlerSierra,
+ casm: compiledOrderHandlerCasm ,
+ constructorCalldata: orderHandlerConstructor,
+ })
+ console.log("OrderHandler Deployed: " + deployOrderHandlerResponse.deploy.contract_address)
+
+ const compiledDepositVaultCasm = json.parse(fs.readFileSync( "./target/dev/satoru_DepositVault.compiled_contract_class.json").toString( "ascii"))
+ const compiledDepositVaultSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DepositVault.contract_class.json").toString( "ascii"))
+ const depositVaultCallData: CallData = new CallData(compiledDepositVaultSierra.abi)
+ const depositVaultConstructor: Calldata = depositVaultCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ })
+ const deployDepositVaultResponse = await account0.declareAndDeploy({
+ contract: compiledDepositVaultSierra,
+ casm: compiledDepositVaultCasm ,
+ constructorCalldata: depositVaultConstructor,
+ })
+ console.log("DepositVault Deployed: " + deployDepositVaultResponse.deploy.contract_address)
+
+ const compiledDepositHandlerCasm = json.parse(fs.readFileSync( "./target/dev/satoru_DepositHandler.compiled_contract_class.json").toString( "ascii"))
+ const compiledDepositHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DepositHandler.contract_class.json").toString( "ascii"))
+ const depositHandlerCallData: CallData = new CallData(compiledDepositHandlerSierra.abi)
+ const depositHandlerConstructor: Calldata = depositHandlerCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ deposit_vault_address: deployDepositVaultResponse.deploy.contract_address,
+ oracle_address: deployOracleResponse.deploy.contract_address,
+ })
+ const deployDepositHandlerResponse = await account0.declareAndDeploy({
+ contract: compiledDepositHandlerSierra,
+ casm: compiledDepositHandlerCasm ,
+ constructorCalldata: depositHandlerConstructor,
+ })
+ console.log("DepositHandler Deployed: " + deployDepositHandlerResponse.deploy.contract_address)
+
+ const compiledWithdrawalVaultCasm = json.parse(fs.readFileSync( "./target/dev/satoru_WithdrawalVault.compiled_contract_class.json").toString( "ascii"))
+ const compiledWithdrawalVaultSierra = json.parse(fs.readFileSync( "./target/dev/satoru_WithdrawalVault.contract_class.json").toString( "ascii"))
+ const withdrawalVaultCallData: CallData = new CallData(compiledWithdrawalVaultSierra.abi)
+ const withdrawalVaultConstructor: Calldata = withdrawalVaultCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ })
+ const deployWithdrawalVaultResponse = await account0.declareAndDeploy({
+ contract: compiledWithdrawalVaultSierra,
+ casm: compiledWithdrawalVaultCasm ,
+ constructorCalldata: withdrawalVaultConstructor,
+ })
+ console.log("WithdrawalVault Deployed: " + deployWithdrawalVaultResponse.deploy.contract_address)
+
+ const compiledWithdrawalHandlerCasm = json.parse(fs.readFileSync( "./target/dev/satoru_WithdrawalHandler.compiled_contract_class.json").toString( "ascii"))
+ const compiledWithdrawalHandlerSierra = json.parse(fs.readFileSync( "./target/dev/satoru_WithdrawalHandler.contract_class.json").toString( "ascii"))
+ const withdrawalHandlerCallData: CallData = new CallData(compiledWithdrawalHandlerSierra.abi)
+ const withdrawalHandlerConstructor: Calldata = withdrawalHandlerCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ withdrawal_vault_address: deployWithdrawalVaultResponse.deploy.contract_address,
+ oracle_address: deployOracleResponse.deploy.contract_address,
+ })
+ const deployWithdrawalHandlerResponse = await account0.declareAndDeploy({
+ contract: compiledWithdrawalHandlerSierra,
+ casm: compiledWithdrawalHandlerCasm ,
+ constructorCalldata: withdrawalHandlerConstructor,
+ })
+ console.log("WithdrawalHandler Deployed: " + deployWithdrawalHandlerResponse.deploy.contract_address)
+
+ const compiledMarketTokenCasm = json.parse(fs.readFileSync( "./target/dev/satoru_MarketToken.compiled_contract_class.json").toString( "ascii"))
+ const compiledMarketTokenSierra = json.parse(fs.readFileSync( "./target/dev/satoru_MarketToken.contract_class.json").toString( "ascii"))
+ try {
+ await account0.declare({
+ contract: compiledMarketTokenSierra,
+ casm: compiledMarketTokenCasm
+ })
+ console.log("MarketToken Declared.")
+ } catch (error) {
+ console.log("Already Declared.")
+ }
+
+ // const marketTokenClassHash = hash.computeCompiledClassHash(compiledMarketTokenCasm)
+ const compiledMarketFactoryCasm = json.parse(fs.readFileSync( "./target/dev/satoru_MarketFactory.compiled_contract_class.json").toString( "ascii"))
+ const compiledMarketFactorySierra = json.parse(fs.readFileSync( "./target/dev/satoru_MarketFactory.contract_class.json").toString( "ascii"))
+ const marketFactoryCallData: CallData = new CallData(compiledMarketFactorySierra.abi)
+ const marketFactoryConstructor: Calldata = marketFactoryCallData.compile("constructor", {
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ market_token_class_hash: "0x0782830d85481434f237378795dc72d42a9295d11e5e8671bd3965dcd67a56ac"
+ })
+ const deployMarketFactoryResponse = await account0.declareAndDeploy({
+ contract: compiledMarketFactorySierra,
+ casm: compiledMarketFactoryCasm ,
+ constructorCalldata: marketFactoryConstructor,
+ })
+ console.log("MarketFactory Deployed: " + deployMarketFactoryResponse.deploy.contract_address)
+
+ const compiledReaderCasm = json.parse(fs.readFileSync( "./target/dev/satoru_Reader.compiled_contract_class.json").toString( "ascii"))
+ const compiledReaderSierra = json.parse(fs.readFileSync( "./target/dev/satoru_Reader.contract_class.json").toString( "ascii"))
+ const readerCallData: CallData = new CallData(compiledReaderSierra.abi)
+ const readerConstructor: Calldata = readerCallData.compile("constructor", {})
+ const deployReaderResponse = await account0.declareAndDeploy({
+ contract: compiledReaderSierra,
+ casm: compiledReaderCasm ,
+ constructorCalldata: readerConstructor,
+ })
+ console.log("Reader Deployed: " + deployReaderResponse.deploy.contract_address)
+
+ const compiledRouterCasm = json.parse(fs.readFileSync( "./target/dev/satoru_Router.compiled_contract_class.json").toString( "ascii"))
+ const compiledRouterSierra = json.parse(fs.readFileSync( "./target/dev/satoru_Router.contract_class.json").toString( "ascii"))
+ const routerCallData: CallData = new CallData(compiledRouterSierra.abi)
+ const routerConstructor: Calldata = routerCallData.compile("constructor", {
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ })
+ const deployRouterResponse = await account0.declareAndDeploy({
+ contract: compiledRouterSierra,
+ casm: compiledRouterCasm ,
+ constructorCalldata: routerConstructor,
+ })
+ console.log("Router Deployed: " + deployRouterResponse.deploy.contract_address)
+
+
+ const compiledExchangeRouterCasm = json.parse(fs.readFileSync( "./target/dev/satoru_ExchangeRouter.compiled_contract_class.json").toString( "ascii"))
+ const compiledExchangeRouterSierra = json.parse(fs.readFileSync( "./target/dev/satoru_ExchangeRouter.contract_class.json").toString( "ascii"))
+ const exchangeRouterCallData: CallData = new CallData(compiledExchangeRouterSierra.abi)
+ const exchangeRouterConstructor: Calldata = exchangeRouterCallData.compile("constructor", {
+ router_address: deployRouterResponse.deploy.contract_address,
+ data_store_address: deployDataStoreResponse.deploy.contract_address,
+ role_store_address: deployRoleStoreResponse.deploy.contract_address,
+ event_emitter_address: deployEventEmitterResponse.deploy.contract_address,
+ deposit_handler_address: deployDepositHandlerResponse.deploy.contract_address,
+ withdrawal_handler_address: deployWithdrawalHandlerResponse.deploy.contract_address,
+ order_handler_address: deployOrderHandlerResponse.deploy.contract_address
+ })
+ const deployExchangeRouterResponse = await account0.declareAndDeploy({
+ contract: compiledExchangeRouterSierra,
+ casm: compiledExchangeRouterCasm ,
+ constructorCalldata: exchangeRouterConstructor,
+ })
+ console.log("ExchangeRouter Deployed: " + deployExchangeRouterResponse.deploy.contract_address)
+
+
+ const roleCall2 = roleStoreContract.populate("grant_role", [account0.address, shortString.encodeShortString("MARKET_KEEPER")])
+ const roleCall3 = roleStoreContract.populate("grant_role", [account0.address, shortString.encodeShortString("ORDER_KEEPER")])
+ const roleCall4 = roleStoreContract.populate("grant_role",
+ [
+ deployOrderHandlerResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall5 = roleStoreContract.populate("grant_role",
+ [
+ deployIncreaseOrderUtilsResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall6 = roleStoreContract.populate("grant_role",
+ [
+ deployDecreaseOrderUtilsResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall7 = roleStoreContract.populate("grant_role",
+ [
+ deploySwapOrderUtilsResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall8 = roleStoreContract.populate("grant_role",
+ [
+ deployDepositHandlerResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall9 = roleStoreContract.populate("grant_role",
+ [
+ deployWithdrawalHandlerResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall10 = roleStoreContract.populate("grant_role",
+ [
+ deploySwapHandlerResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const roleCall11 = roleStoreContract.populate("grant_role",
+ [
+ deployExchangeRouterResponse.deploy.contract_address,
+ shortString.encodeShortString("CONTROLLER")
+ ]
+ )
+ const grant_role_tx2 = await roleStoreContract.grant_role(roleCall2.calldata)
+ await provider.waitForTransaction(grant_role_tx2.transaction_hash)
+ const grant_role_tx3 = await roleStoreContract.grant_role(roleCall3.calldata)
+ await provider.waitForTransaction(grant_role_tx3.transaction_hash)
+ const grant_role_tx4 = await roleStoreContract.grant_role(roleCall4.calldata)
+ await provider.waitForTransaction(grant_role_tx4.transaction_hash)
+ const grant_role_tx5 = await roleStoreContract.grant_role(roleCall5.calldata)
+ await provider.waitForTransaction(grant_role_tx5.transaction_hash)
+ const grant_role_tx6 = await roleStoreContract.grant_role(roleCall6.calldata)
+ await provider.waitForTransaction(grant_role_tx6.transaction_hash)
+ const grant_role_tx7 = await roleStoreContract.grant_role(roleCall7.calldata)
+ await provider.waitForTransaction(grant_role_tx7.transaction_hash)
+ const grant_role_tx8 = await roleStoreContract.grant_role(roleCall8.calldata)
+ await provider.waitForTransaction(grant_role_tx8.transaction_hash)
+ const grant_role_tx9 = await roleStoreContract.grant_role(roleCall9.calldata)
+ await provider.waitForTransaction(grant_role_tx9.transaction_hash)
+ const grant_role_tx10 = await roleStoreContract.grant_role(roleCall10.calldata)
+ await provider.waitForTransaction(grant_role_tx10.transaction_hash)
+ const grant_role_tx11 = await roleStoreContract.grant_role(roleCall11.calldata)
+ await provider.waitForTransaction(grant_role_tx11.transaction_hash)
+
+ console.log("Roles granted.")
+}
+
+deploy()
\ No newline at end of file
diff --git a/scripts/app/test2.ts b/scripts/app/test2.ts
new file mode 100644
index 00000000..d33d6eef
--- /dev/null
+++ b/scripts/app/test2.ts
@@ -0,0 +1,74 @@
+import { Account, hash, Contract, json, Calldata, CallData, RpcProvider, shortString, ec, uint256 } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function deploy() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const eth: string = "0x3fa46510b749925fb3fa02e98195909683eaee8d4c982cc647cd98a7f160905"
+ const usdc: string = "0x636d15cd4dfe130c744282f86496077e089cb9dc96ccc37bf0d85ea358a5760"
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ const marketTokenAddress = "0x68ad9440759f0bd0367e407d53b5e5c32203590f12d54ed8968f48fee0cf636"
+ console.log("Deploying with Account: " + account0Address)
+ console.log("RPC: " + providerUrl)
+
+ const dataStoreAddress = process.env.DATA_STORE as string
+ const compiledDataStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_DataStore.contract_class.json").toString( "ascii"))
+ const dataStoreContract = new Contract(compiledDataStoreSierra.abi, dataStoreAddress, provider)
+ dataStoreContract.connect(account0);
+
+ // console.log(await dataStoreContract.get_u256(await dataStoreContract.get_pool_amount_key(marketTokenAddress, usdc)))
+ // console.log(await dataStoreContract.get_u256(await dataStoreContract.get_pool_amount_key(marketTokenAddress, eth)))
+ // const hashUSDC = await dataStoreContract.get_max_pool_amount_key(marketTokenAddress, usdc)
+ // const dataCall4 = dataStoreContract.populate(
+ // "set_u256",
+ // [await dataStoreContract.get_pool_amount_key(marketTokenAddress, usdc), 25000000000000000000000000n]
+ // )
+ // const setAddressTx4 = await dataStoreContract.set_u256(dataCall4.calldata)
+ // await provider.waitForTransaction(setAddressTx4.transaction_hash)
+
+ // const dataCall8 = dataStoreContract.populate(
+ // "set_u256",
+ // [
+ // await dataStoreContract.get_max_open_interest_key(
+ // marketTokenAddress,
+ // true
+ // ),
+ // 1000000000000000000000000000000000000000000000000000n
+ // ]
+ // )
+ // const setAddressTx8 = await dataStoreContract.set_u256(dataCall8.calldata)
+ // await provider.waitForTransaction(setAddressTx8.transaction_hash)
+
+ // const dataCall5 = dataStoreContract.populate(
+ // "set_u256",
+ // [await dataStoreContract.get_pool_amount_key(marketTokenAddress, eth), 50000000000000000001000000n]
+ // )
+ // const setAddressTx5 = await dataStoreContract.set_u256(dataCall5.calldata)
+ // await provider.waitForTransaction(setAddressTx5.transaction_hash)
+
+ const compiledRoleStoreSierra = json.parse(fs.readFileSync( "./target/dev/satoru_RoleStore.contract_class.json").toString( "ascii"))
+ const roleStoreContract = new Contract(compiledRoleStoreSierra.abi, process.env.ROLE_STORE as string, provider)
+ roleStoreContract.connect(account0);
+
+ const roleCall4 = roleStoreContract.populate("grant_role", ["0x04db27f09ae33b3f2720f730e03206050a62ca48c6d651d2853024cd21270ed3" as string, shortString.encodeShortString("CONTROLLER")])
+ const grant_role_tx4 = await roleStoreContract.grant_role(roleCall4.calldata)
+ await provider.waitForTransaction(grant_role_tx4.transaction_hash)
+
+ // const compiledOracleSierra = json.parse(fs.readFileSync( "./target/dev/satoru_Oracle.contract_class.json").toString( "ascii"))
+
+ // const oracleContract = new Contract(compiledOracleSierra.abi, process.env.ORACLE as string, provider);
+ // oracleContract.connect(account0);
+ // const setPrimaryPriceCall1 = oracleContract.populate("set_primary_price", [eth, uint256.bnToUint256(6000)])
+ // const setPrimaryPriceTx1 = await oracleContract.set_primary_price(setPrimaryPriceCall1.calldata);
+ // await provider.waitForTransaction(setPrimaryPriceTx1.transaction_hash)
+
+}
+
+deploy()
\ No newline at end of file
diff --git a/scripts/app/testDeploy.ts b/scripts/app/testDeploy.ts
new file mode 100644
index 00000000..97d02316
--- /dev/null
+++ b/scripts/app/testDeploy.ts
@@ -0,0 +1,35 @@
+import { Account, hash, Contract, json, Calldata, CallData, RpcProvider, shortString, ec } from "starknet"
+import fs from 'fs'
+import dotenv from 'dotenv'
+
+dotenv.config()
+
+async function deploy() {
+ // connect provider
+ const providerUrl = process.env.PROVIDER_URL
+ const provider = new RpcProvider({ nodeUrl: providerUrl! })
+ // connect your account. To adapt to your own account :
+ const privateKey0: string = process.env.ACCOUNT_PRIVATE as string
+ const account0Address: string = process.env.ACCOUNT_PUBLIC as string
+ const account0 = new Account(provider, account0Address!, privateKey0!)
+ console.log("Deploying with Account: " + account0Address)
+ console.log("RPC: " + providerUrl)
+
+
+ const compiledReaderCasm = json.parse(fs.readFileSync( "./target/dev/satoru_ReferralStorage.compiled_contract_class.json").toString( "ascii"))
+ const compiledReferralStorageSierra = json.parse(fs.readFileSync("./target/dev/satoru_ReferralStorage.contract_class.json").toString( "ascii"))
+ const referralStorageCallData: CallData = new CallData(compiledReferralStorageSierra.abi)
+ const referralStorageConstructor: Calldata = referralStorageCallData.compile("constructor", {
+ event_emitter_address: process.env.EVENT_EMITTER as string
+ })
+ const deployReferralStorageResponse = await account0.declareAndDeploy({
+ contract: compiledReferralStorageSierra,
+ casm: compiledReaderCasm ,
+ constructorCalldata: referralStorageConstructor,
+ })
+ console.log("Reader Deployed: " + deployReferralStorageResponse.deploy.contract_address)
+
+
+}
+
+deploy()
\ No newline at end of file
diff --git a/scripts/bank/deploy_StrictBank_contract.sh b/scripts/bank/deploy_StrictBank_contract.sh
new file mode 100644
index 00000000..3057d467
--- /dev/null
+++ b/scripts/bank/deploy_StrictBank_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for strict_bank.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_StrictBank.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/bank/deploy_bank_contract.sh b/scripts/bank/deploy_bank_contract.sh
new file mode 100644
index 00000000..21796eca
--- /dev/null
+++ b/scripts/bank/deploy_bank_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for bank.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Bank.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/config/deploy_config_contract.sh b/scripts/config/deploy_config_contract.sh
new file mode 100644
index 00000000..e8bcf550
--- /dev/null
+++ b/scripts/config/deploy_config_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for config.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Config.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/config/deploy_timelock_contract.sh b/scripts/config/deploy_timelock_contract.sh
new file mode 100644
index 00000000..936275ce
--- /dev/null
+++ b/scripts/config/deploy_timelock_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for timelock.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Timelock.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/data/deploy_data_store_contract.sh b/scripts/data/deploy_data_store_contract.sh
new file mode 100755
index 00000000..b730278e
--- /dev/null
+++ b/scripts/data/deploy_data_store_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for data_store.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_DataStore.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/deploy_role_store_contract.sh b/scripts/deploy_role_store_contract.sh
deleted file mode 100644
index d9567d00..00000000
--- a/scripts/deploy_role_store_contract.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-# Deployment script for role_store.cairo
-
-# Declare the contract and capture the command output
-command_output=$(starkli declare ../target/dev/satoru_RoleStore.sierra.json)
-
-# Define the character to split the command output
-from_char=":"
-
-# Extract the class hash from the command output
-class_hash=$(echo "$command_output" | sed 's/.*'$from_char'//')
-
-# Deploy the contract using the extracted class hash
-starkli deploy $class_hash
\ No newline at end of file
diff --git a/scripts/deposit/deploy_deposit_vault_contract.sh b/scripts/deposit/deploy_deposit_vault_contract.sh
new file mode 100755
index 00000000..55fb5b41
--- /dev/null
+++ b/scripts/deposit/deploy_deposit_vault_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for deposit_vault.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_DepositVault.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/event/deploy_event_emitter_contract.sh b/scripts/event/deploy_event_emitter_contract.sh
new file mode 100755
index 00000000..c63f6396
--- /dev/null
+++ b/scripts/event/deploy_event_emitter_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for event_emitter.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_EventEmitter.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_adl_handler_contract.sh b/scripts/exchange/deploy_adl_handler_contract.sh
new file mode 100644
index 00000000..8747b6d2
--- /dev/null
+++ b/scripts/exchange/deploy_adl_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for adl_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_AdlHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 $8 $9 $10 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_base_order_handler_contract.sh b/scripts/exchange/deploy_base_order_handler_contract.sh
new file mode 100644
index 00000000..0d046e06
--- /dev/null
+++ b/scripts/exchange/deploy_base_order_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for base_order_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_BaseOrderHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 $8 $9 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_deposit_handler_contract.sh b/scripts/exchange/deploy_deposit_handler_contract.sh
new file mode 100644
index 00000000..442b31bd
--- /dev/null
+++ b/scripts/exchange/deploy_deposit_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for deposit_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_DepositHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_liquidation_handler_contract.sh b/scripts/exchange/deploy_liquidation_handler_contract.sh
new file mode 100644
index 00000000..cff1a5fe
--- /dev/null
+++ b/scripts/exchange/deploy_liquidation_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for liquidation_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_LiquidationHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 $8 $9 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_order_handler_contract.sh b/scripts/exchange/deploy_order_handler_contract.sh
new file mode 100644
index 00000000..72c5ab5d
--- /dev/null
+++ b/scripts/exchange/deploy_order_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for order_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_OrderHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 $8 $9 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/exchange/deploy_withdrawal_handler_contract.sh b/scripts/exchange/deploy_withdrawal_handler_contract.sh
new file mode 100644
index 00000000..5e1a9327
--- /dev/null
+++ b/scripts/exchange/deploy_withdrawal_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for withdrawal_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_WithdrawalHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/fee/deploy_fee_handler_contract.sh b/scripts/fee/deploy_fee_handler_contract.sh
new file mode 100755
index 00000000..58958bdd
--- /dev/null
+++ b/scripts/fee/deploy_fee_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for fee_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_FeeHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/market/deploy_market_factory_contract.sh b/scripts/market/deploy_market_factory_contract.sh
new file mode 100644
index 00000000..d43db089
--- /dev/null
+++ b/scripts/market/deploy_market_factory_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for market_factory.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_MarketFactory.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/market/deploy_market_token_contract.sh b/scripts/market/deploy_market_token_contract.sh
new file mode 100644
index 00000000..08563d75
--- /dev/null
+++ b/scripts/market/deploy_market_token_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for market_token.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_MarketToken.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/mock/deploy_governable_contract.sh b/scripts/mock/deploy_governable_contract.sh
new file mode 100644
index 00000000..a7f802ee
--- /dev/null
+++ b/scripts/mock/deploy_governable_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for governable.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Governable.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/mock/deploy_referral_storage.sh b/scripts/mock/deploy_referral_storage.sh
new file mode 100644
index 00000000..89976652
--- /dev/null
+++ b/scripts/mock/deploy_referral_storage.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for referral_storage.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_ReferralStorage.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/oracle/deploy_oracle_contract.sh b/scripts/oracle/deploy_oracle_contract.sh
new file mode 100755
index 00000000..f156cde6
--- /dev/null
+++ b/scripts/oracle/deploy_oracle_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for data_store.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Oracle.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/oracle/deploy_oracle_store_contract.sh b/scripts/oracle/deploy_oracle_store_contract.sh
new file mode 100755
index 00000000..947f165d
--- /dev/null
+++ b/scripts/oracle/deploy_oracle_store_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for oracle_store.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_OracleStore.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/oracle/deploy_price_feed_contract.sh b/scripts/oracle/deploy_price_feed_contract.sh
new file mode 100644
index 00000000..0764fcb1
--- /dev/null
+++ b/scripts/oracle/deploy_price_feed_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for price_feed.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_PriceFeed.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/order/deploy_order_vault_contract.sh b/scripts/order/deploy_order_vault_contract.sh
new file mode 100755
index 00000000..84374869
--- /dev/null
+++ b/scripts/order/deploy_order_vault_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for order_vault.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_OrderVault.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/reader/deploy_reader_contract.sh b/scripts/reader/deploy_reader_contract.sh
new file mode 100644
index 00000000..36e7b56d
--- /dev/null
+++ b/scripts/reader/deploy_reader_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for reader.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Reader.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/role/deploy_role_module_contract.sh b/scripts/role/deploy_role_module_contract.sh
new file mode 100644
index 00000000..9f614190
--- /dev/null
+++ b/scripts/role/deploy_role_module_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for role_module.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_RoleModule.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/role/deploy_role_store_contract.sh b/scripts/role/deploy_role_store_contract.sh
new file mode 100755
index 00000000..8639bb29
--- /dev/null
+++ b/scripts/role/deploy_role_store_contract.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Deployment script for role_store.cairo
+command_output=$(starkli declare ../../target/dev/satoru_RoleStore.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/router/deploy_exchange_router_contract.sh b/scripts/router/deploy_exchange_router_contract.sh
new file mode 100644
index 00000000..63109871
--- /dev/null
+++ b/scripts/router/deploy_exchange_router_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for exchange_router.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_ExchangeRouter.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 $5 $6 $7 $8 $9 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/router/deploy_router_contract.sh b/scripts/router/deploy_router_contract.sh
new file mode 100644
index 00000000..861f5a60
--- /dev/null
+++ b/scripts/router/deploy_router_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for router.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_Router.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/swap/deploy_swap_handler_contract.sh b/scripts/swap/deploy_swap_handler_contract.sh
new file mode 100644
index 00000000..e1c7df81
--- /dev/null
+++ b/scripts/swap/deploy_swap_handler_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for swap_handler.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_SwapHandler.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 $4 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/scripts/withdrawal/deploy_withdrawal_vault_contract.sh b/scripts/withdrawal/deploy_withdrawal_vault_contract.sh
new file mode 100644
index 00000000..6e33a342
--- /dev/null
+++ b/scripts/withdrawal/deploy_withdrawal_vault_contract.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Deployment script for withdrawal_vault.cairo
+
+# Declare the contract and capture the command output
+command_output=$(starkli declare ../../target/dev/satoru_WithdrawalVault.sierra.json --network=goerli-1 --compiler-version=2.1.0 --account $1 --keystore $2)
+
+from_string="Class hash declared:"
+class_hash="${command_output#*$from_string}"
+
+# Deploy the contract using the extracted class hash
+starkli deploy $class_hash $3 --network=goerli-1 --account $1 --keystore $2
\ No newline at end of file
diff --git a/src/adl/adl_utils.cairo b/src/adl/adl_utils.cairo
index b7408bb8..60d3412a 100644
--- a/src/adl/adl_utils.cairo
+++ b/src/adl/adl_utils.cairo
@@ -2,8 +2,8 @@
//! This is particularly for markets with an index token that is different from
//! the long token.
//!
-//! For example, if there is a DOGE / USD perp market with ETH as the long token
-//! it would be possible for the price of DOGE to increase faster than the price of
+//! For example, if there is a STRK / USD perp market with ETH as the long token
+//! it would be possible for the price of STRK to increase faster than the price of
//! ETH.
//!
//! In this scenario, profitable positions should be closed through ADL to ensure
@@ -13,24 +13,25 @@
// IMPORTS
// *************************************************************************
// Core lib imports.
-use starknet::{get_caller_address, ContractAddress};
+use starknet::{get_caller_address, ContractAddress, contract_address_const};
use integer::BoundedInt;
// Local imports.
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::event::{event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait},};
use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait};
use satoru::market::market_utils::{
- MarketPrices, get_enabled_market, get_market_prices, is_pnl_factor_exceeded_direct
+ MarketPrices, get_enabled_market, get_market_prices, is_pnl_factor_exceeded_check
};
use satoru::adl::error::AdlError;
use satoru::data::keys;
-use satoru::utils::arrays::u64_are_gte;
+use satoru::utils::arrays::are_gte_u64;
use satoru::position::position_utils;
use satoru::position::position::Position;
use satoru::order::order::{Order, OrderType, DecreasePositionSwapType};
use satoru::nonce::nonce_utils;
use satoru::callback::callback_utils::get_saved_callback_contract;
use satoru::utils::span32::{Span32, Array32Trait};
+use satoru::utils::i256::i256;
/// CreateAdlOrderParams struct used in createAdlOrder to avoid stack
#[derive(Drop, Copy, starknet::Store, Serde)]
struct CreateAdlOrderParams {
@@ -47,7 +48,7 @@ struct CreateAdlOrderParams {
/// Whether the position is long or short.
is_long: bool,
/// The size to reduce the position by.
- size_delta_usd: u128,
+ size_delta_usd: u256,
/// The block to set the order's updated_at_block.
updated_at_block: u64,
}
@@ -90,7 +91,7 @@ fn update_adl_state(
) {
let latest_adl_block = get_latest_adl_block(data_store, market, is_long);
assert(
- u64_are_gte(max_oracle_block_numbers, latest_adl_block),
+ are_gte_u64(max_oracle_block_numbers, latest_adl_block),
AdlError::ORACLE_BLOCK_NUMBERS_ARE_SMALLER_THAN_REQUIRED
);
let _market = get_enabled_market(data_store, market);
@@ -99,7 +100,7 @@ fn update_adl_state(
// it is possible for a pool to be in a state where withdrawals and ADL is not allowed
// this is similar to the case where there is a large amount of open positions relative
// to the amount of tokens in the pool
- let (should_enable_adl, pnl_to_pool_factor, max_pnl_factor) = is_pnl_factor_exceeded_direct(
+ let (should_enable_adl, pnl_to_pool_factor, max_pnl_factor) = is_pnl_factor_exceeded_check(
data_store, _market, prices, is_long, keys::max_pnl_factor_for_adl()
);
set_adl_enabled(data_store, market, is_long, should_enable_adl);
@@ -126,19 +127,9 @@ fn create_adl_order(params: CreateAdlOrderParams) -> felt252 {
let positon_key = position_utils::get_position_key(
params.account, params.market, params.collateral_token, params.is_long
);
- let position_result = params.data_store.get_position(positon_key);
- let mut position: Position = Default::default();
+ let position = params.data_store.get_position(positon_key);
- // Check if the position is valid
- match position_result {
- Option::Some(pos) => {
- assert(params.size_delta_usd <= pos.size_in_usd, AdlError::INVALID_SIZE_DELTA_FOR_ADL);
- position = pos;
- },
- Option::None => {
- panic_with_felt252(AdlError::POSTION_NOT_VALID);
- }
- }
+ assert(params.size_delta_usd <= position.size_in_usd, AdlError::INVALID_SIZE_DELTA_FOR_ADL);
// no slippage is set for this order, it may be preferrable for ADL orders
// to be executed, in case of large price impact, the user could be refunded
@@ -157,8 +148,8 @@ fn create_adl_order(params: CreateAdlOrderParams) -> felt252 {
// swapping the pnl token to the collateral token helps to ensure fees can be paid
// using the realized profit
- let acceptable_price_: u128 = if position.is_long {
- 0_u128
+ let acceptable_price_: u256 = if position.is_long {
+ 0_u256
} else {
BoundedInt::max()
};
@@ -172,7 +163,7 @@ fn create_adl_order(params: CreateAdlOrderParams) -> felt252 {
callback_contract: get_saved_callback_contract(
params.data_store, params.account, params.market
),
- ui_fee_receiver: 0.try_into().unwrap(),
+ ui_fee_receiver: contract_address_const::<0>(),
market: params.market,
initial_collateral_token: position.collateral_token,
swap_path: Array32Trait::::span32(@ArrayTrait::new()),
@@ -181,11 +172,7 @@ fn create_adl_order(params: CreateAdlOrderParams) -> felt252 {
trigger_price: 0,
acceptable_price: acceptable_price_,
execution_fee: 0,
- callback_gas_limit: params
- .data_store
- .get_felt252(keys::max_callback_gas_limit())
- .try_into()
- .unwrap(),
+ callback_gas_limit: params.data_store.get_felt252(keys::max_callback_gas_limit()).into(),
min_output_amount: 0,
updated_at_block: params.updated_at_block,
is_long: position.is_long,
@@ -209,11 +196,11 @@ fn validate_adl(
is_long: bool,
max_oracle_block_numbers: Span
) {
- let is_adl_enabled = get_adl_enabled(data_store, market, is_long);
+ let is_adl_enabled = get_is_adl_enabled(data_store, market, is_long);
assert(is_adl_enabled, AdlError::ADL_NOT_ENABLED);
let latest_block = get_latest_adl_block(data_store, market, is_long);
assert(
- u64_are_gte(max_oracle_block_numbers, latest_block),
+ are_gte_u64(max_oracle_block_numbers, latest_block),
AdlError::ORACLE_BLOCK_NUMBERS_ARE_SMALLER_THAN_REQUIRED
);
}
@@ -228,7 +215,10 @@ fn validate_adl(
fn get_latest_adl_block(
data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
) -> u64 {
- data_store.get_u128(keys::latest_adl_block_key(market, is_long)).try_into().unwrap()
+ data_store
+ .get_u256(keys::latest_adl_block_key(market, is_long))
+ .try_into()
+ .expect('get_u256 into u64 failed')
}
/// Set the latest block at which the ADL flag was updated.
@@ -242,7 +232,7 @@ fn get_latest_adl_block(
fn set_latest_adl_block(
data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool, value: u64
) -> u64 {
- data_store.set_u128(keys::latest_adl_block_key(market, is_long), value.into());
+ data_store.set_u256(keys::latest_adl_block_key(market, is_long), value.into());
value
}
@@ -253,18 +243,10 @@ fn set_latest_adl_block(
/// * `is_long` - Indicates whether to check the long or short side of the market.
/// # Returns
/// Return whether ADL is enabled.
-fn get_adl_enabled(
+fn get_is_adl_enabled(
data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
-) -> bool { // TODO
- let result = data_store.get_bool(keys::is_adl_enabled_key(market, is_long));
- match result {
- Option::Some(data) => {
- return data;
- },
- Option::None => {
- return false;
- }
- }
+) -> bool {
+ data_store.get_bool(keys::is_adl_enabled_key(market, is_long))
}
/// Set whether ADL is enabled.
@@ -294,8 +276,8 @@ fn emit_adl_state_updated(
event_emitter: IEventEmitterDispatcher,
market: ContractAddress,
is_long: bool,
- pnl_to_pool_factor: i128,
- max_pnl_factor: u128,
+ pnl_to_pool_factor: i256,
+ max_pnl_factor: u256,
should_enable_adl: bool
) {
event_emitter
diff --git a/src/adl/error.cairo b/src/adl/error.cairo
index 78adb5a5..30ca0f29 100644
--- a/src/adl/error.cairo
+++ b/src/adl/error.cairo
@@ -3,5 +3,5 @@ mod AdlError {
'block_no_smaller_than_required';
const INVALID_SIZE_DELTA_FOR_ADL: felt252 = 'invalid_size_delta_for_adl';
const ADL_NOT_ENABLED: felt252 = 'adl_not_enabled';
- const POSTION_NOT_VALID: felt252 = 'position_not_valid';
+ const POSITION_NOT_VALID: felt252 = 'position_not_valid';
}
diff --git a/src/bank/bank.cairo b/src/bank/bank.cairo
index 922089e0..800afad8 100644
--- a/src/bank/bank.cairo
+++ b/src/bank/bank.cairo
@@ -7,6 +7,7 @@
// Core lib imports.
use core::traits::Into;
use starknet::ContractAddress;
+use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
// *************************************************************************
// Interface of the `Bank` contract.
@@ -29,7 +30,11 @@ trait IBank {
/// * `receiver` - The address of the receiver.
/// * `amount` - The amount of tokens to transfer.
fn transfer_out(
- ref self: TContractState, token: ContractAddress, receiver: ContractAddress, amount: u128,
+ ref self: TContractState,
+ sender: ContractAddress,
+ token: ContractAddress,
+ receiver: ContractAddress,
+ amount: u256,
);
}
@@ -45,14 +50,14 @@ mod Bank {
get_caller_address, get_contract_address, ContractAddress, contract_address_const
};
- use debug::PrintTrait;
-
// Local imports.
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use super::IBank;
use satoru::bank::error::BankError;
use satoru::role::role_module::{RoleModule, IRoleModule};
- use satoru::token::token_utils::transfer;
+ // use satoru::token::token_utils::transfer;
+ use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
+
// *************************************************************************
// STORAGE
@@ -60,7 +65,7 @@ mod Bank {
#[storage]
struct Storage {
/// Interface to interact with the `DataStore` contract.
- data_store: IDataStoreDispatcher,
+ data_store: IDataStoreDispatcher
}
// *************************************************************************
@@ -84,7 +89,7 @@ mod Bank {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl BankImpl of super::IBank {
fn initialize(
ref self: ContractState,
@@ -103,15 +108,16 @@ mod Bank {
fn transfer_out(
ref self: ContractState,
+ sender: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
- amount: u128,
+ amount: u256,
) {
// assert that caller is a controller
- let mut role_module: RoleModule::ContractState =
- RoleModule::unsafe_new_contract_state();
- role_module.only_controller();
- self.transfer_out_internal(token, receiver, amount);
+ // let mut role_module: RoleModule::ContractState =
+ // RoleModule::unsafe_new_contract_state();
+ // role_module.only_controller();
+ self.transfer_out_internal(sender, token, receiver, amount);
}
}
@@ -124,13 +130,15 @@ mod Bank {
/// * `receiver` - receiver the address to transfer to
fn transfer_out_internal(
ref self: ContractState,
+ sender: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
- amount: u128,
+ amount: u256,
) {
// check that receiver is not this contract
assert(receiver != get_contract_address(), BankError::SELF_TRANSFER_NOT_SUPPORTED);
- transfer(self.data_store.read(), token, receiver, amount);
+ // transfer(self.data_store.read(), token, receiver, amount); // TODO check double send
+ IERC20Dispatcher { contract_address: token }.transfer_from(sender, receiver, amount);
}
}
}
diff --git a/src/bank/strict_bank.cairo b/src/bank/strict_bank.cairo
index 18689369..c40b229b 100644
--- a/src/bank/strict_bank.cairo
+++ b/src/bank/strict_bank.cairo
@@ -5,8 +5,9 @@
// *************************************************************************
// Core lib imports.
-use core::traits::Into;
-use starknet::ContractAddress;
+use traits::{Into, TryInto};
+use starknet::{ContractAddress, get_contract_address};
+use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
// *************************************************************************
// Interface of the `StrictBank` contract.
@@ -29,17 +30,29 @@ trait IStrictBank {
/// * `receiver` - The address of the receiver.
/// * `amount` - The amount of tokens to transfer.
fn transfer_out(
- ref self: TContractState, token: ContractAddress, receiver: ContractAddress, amount: u128,
+ ref self: TContractState,
+ sender: ContractAddress,
+ token: ContractAddress,
+ receiver: ContractAddress,
+ amount: u256,
);
- /// Updates the `token_balances` in case of token burns or similar balance changes.
- /// The `prev_balance` is not validated to be more than the `next_balance` as this
- /// could allow someone to block this call by transferring into the contract.
+ /// Records a token transfer into the contract
+ /// # Arguments
+ /// * `token` - The token to record the transfer for
+ /// # Return
+ /// The amount of tokens transferred in
+ fn record_transfer_in(ref self: TContractState, token: ContractAddress) -> u256;
+
+ /// this can be used to update the tokenBalances in case of token burns
+ /// or similar balance changes
+ /// the prevBalance is not validated to be more than the nextBalance as this
+ /// could allow someone to block this call by transferring into the contract
/// # Arguments
- /// * `token` - The token to record the burn for.
- /// # Returns
- /// * The new balance.
- fn sync_token_balance(ref self: TContractState, token: ContractAddress) -> u128;
+ /// * `token` - The token to record the burn for
+ /// # Return
+ /// The new balance
+ fn sync_token_balance(ref self: TContractState, token: starknet::ContractAddress) -> u256;
}
#[starknet::contract]
@@ -49,19 +62,25 @@ mod StrictBank {
// *************************************************************************
// Core lib imports.
- use starknet::{get_caller_address, ContractAddress, contract_address_const};
-
- use debug::PrintTrait;
+ use core::traits::TryInto;
+ use starknet::{
+ get_caller_address, get_contract_address, ContractAddress, contract_address_const
+ };
// Local imports.
use satoru::bank::bank::{Bank, IBank};
use super::IStrictBank;
+ use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
+ use satoru::role::role_module::{RoleModule, IRoleModule};
+ use debug::PrintTrait;
// *************************************************************************
// STORAGE
// *************************************************************************
#[storage]
- struct Storage {}
+ struct Storage {
+ token_balances: LegacyMap::,
+ }
// *************************************************************************
// CONSTRUCTOR
@@ -79,11 +98,10 @@ mod StrictBank {
self.initialize(data_store_address, role_store_address);
}
-
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl StrictBank of super::IStrictBank {
fn initialize(
ref self: ContractState,
@@ -96,16 +114,71 @@ mod StrictBank {
fn transfer_out(
ref self: ContractState,
+ sender: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
- amount: u128,
+ amount: u256,
) {
let mut state: Bank::ContractState = Bank::unsafe_new_contract_state();
- IBank::transfer_out(ref state, token, receiver, amount);
+ IBank::transfer_out(ref state, sender, token, receiver, amount);
+ self.after_transfer_out_infernal(token);
+ }
+
+ fn sync_token_balance(ref self: ContractState, token: ContractAddress) -> u256 {
+ // assert that caller is a controller
+ let mut role_module: RoleModule::ContractState =
+ RoleModule::unsafe_new_contract_state();
+ role_module.only_controller();
+
+ let this_contract = get_contract_address();
+ let next_balance: u256 = IERC20Dispatcher { contract_address: token }
+ .balance_of(this_contract)
+ .try_into()
+ .unwrap();
+ self.token_balances.write(token, next_balance);
+ next_balance
+ }
+
+ fn record_transfer_in(ref self: ContractState, token: ContractAddress) -> u256 {
+ // assert that caller is a controller
+ let mut role_module: RoleModule::ContractState =
+ RoleModule::unsafe_new_contract_state();
+ role_module.only_controller();
+
+ self.record_transfer_in_internal(token)
+ }
+ }
+
+ #[generate_trait]
+ impl PrivateMethods of PrivateMethodsTrait {
+ /// Transfer tokens from this contract to a receiver
+ /// # Arguments
+ /// * `token` - token the token to transfer
+ fn after_transfer_out_infernal(ref self: ContractState, token: starknet::ContractAddress) {
+ let this_contract = get_contract_address();
+ let balance: u256 = IERC20Dispatcher { contract_address: token }
+ .balance_of(this_contract)
+ .try_into()
+ .unwrap();
+ self.token_balances.write(token, balance);
}
- fn sync_token_balance(ref self: ContractState, token: ContractAddress) -> u128 {
- 0
+ /// Records a token transfer into the contract
+ /// # Arguments
+ /// * `token` - The token to record the transfer for
+ /// # Return
+ /// The amount of tokens transferred in
+ fn record_transfer_in_internal(
+ ref self: ContractState, token: starknet::ContractAddress
+ ) -> u256 {
+ let prev_balance: u256 = self.token_balances.read(token);
+ let this_contract = get_contract_address();
+ let next_balance: u256 = IERC20Dispatcher { contract_address: token }
+ .balance_of(this_contract)
+ .try_into()
+ .unwrap();
+ self.token_balances.write(token, next_balance);
+ next_balance - prev_balance
}
}
}
diff --git a/src/callback/callback_utils.cairo b/src/callback/callback_utils.cairo
index 23d21d83..213b0f32 100644
--- a/src/callback/callback_utils.cairo
+++ b/src/callback/callback_utils.cairo
@@ -23,7 +23,7 @@ use starknet::ContractAddress;
// Local imports.
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::data::keys;
-use satoru::event::event_utils::EventLogData;
+use satoru::event::event_utils::{LogData, LogDataTrait};
use satoru::order::order::Order;
use satoru::deposit::deposit::Deposit;
use satoru::withdrawal::withdrawal::Withdrawal;
@@ -38,6 +38,7 @@ use satoru::callback::deposit_callback_receiver::interface::{
use satoru::callback::withdrawal_callback_receiver::interface::{
IWithdrawalCallbackReceiverDispatcher, IWithdrawalCallbackReceiverDispatcherTrait
};
+use integer::U256TryIntoFelt252;
/// Validate that the callback_gas_limit is less than the max specified value.
/// This is to prevent callback gas limits which are larger than the max gas limits per block
@@ -45,14 +46,14 @@ use satoru::callback::withdrawal_callback_receiver::interface::{
/// # Arguments
/// * `data_store` - The data store to use.
/// * `callback_gas_limit` - The callback gas limit.
-fn validate_callback_gas_limit(data_store: IDataStoreDispatcher, callback_gas_limit: u128) {
- let max_callback_gas_limit = data_store.get_u128(keys::max_callback_gas_limit());
+fn validate_callback_gas_limit(data_store: IDataStoreDispatcher, callback_gas_limit: u256) {
+ let max_callback_gas_limit = data_store.get_u256(keys::max_callback_gas_limit());
if callback_gas_limit > max_callback_gas_limit {
panic(
array![
CallbackError::MAX_CALLBACK_GAS_LIMIT_EXCEEDED,
- callback_gas_limit.into(),
- max_callback_gas_limit.into()
+ callback_gas_limit.try_into().expect('u256 into felt failed'),
+ max_callback_gas_limit.try_into().expect('u256 into felt failed')
]
);
}
@@ -91,119 +92,99 @@ fn get_saved_callback_contract(
/// # Arguments
/// * `key` - They key of the deposit.
/// * `deposit` - The deposit that was executed.
-/// * `event_data` - The event log data.
-fn after_deposit_execution(
- key: felt252, deposit: Deposit, event_data: EventLogData, event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_deposit_execution(key: felt252, deposit: Deposit, mut log_data: LogData) {
if !is_valid_callback_contract(deposit.callback_contract) {
return;
}
let dispatcher = IDepositCallbackReceiverDispatcher {
contract_address: deposit.callback_contract
};
- dispatcher.after_deposit_execution(key, deposit, event_data)
+ dispatcher.after_deposit_execution(key, deposit, log_data.serialize_into())
}
/// Called after a deposit cancellation.
/// # Arguments
/// * `key` - They key of the deposit.
/// * `deposit` - The deposit that was cancelled.
-/// * `event_data` - The event log data.
-fn after_deposit_cancellation(
- key: felt252, deposit: Deposit, event_data: EventLogData, event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_deposit_cancellation(key: felt252, deposit: Deposit, mut log_data: LogData) {
if !is_valid_callback_contract(deposit.callback_contract) {
return;
}
let dispatcher = IDepositCallbackReceiverDispatcher {
contract_address: deposit.callback_contract
};
- dispatcher.after_deposit_cancellation(key, deposit, event_data)
+ dispatcher.after_deposit_cancellation(key, deposit, log_data.serialize_into())
}
/// Called after a withdrawal execution.
/// # Arguments
/// * `key` - They key of the withdrawal.
/// * `withdrawal` - The withdrawal that was executed.
-/// * `event_data` - The event log data.
-fn after_withdrawal_execution(
- key: felt252,
- withdrawal: Withdrawal,
- event_data: EventLogData,
- event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_withdrawal_execution(key: felt252, withdrawal: Withdrawal, mut log_data: LogData) {
if !is_valid_callback_contract(withdrawal.callback_contract) {
return;
}
let dispatcher = IWithdrawalCallbackReceiverDispatcher {
contract_address: withdrawal.callback_contract
};
- dispatcher.after_withdrawal_execution(key, withdrawal, event_data)
+ dispatcher.after_withdrawal_execution(key, withdrawal, log_data.serialize_into())
}
/// Called after an withdrawal cancellation.
/// # Arguments
/// * `key` - They key of the withdrawal.
/// * `withdrawal` - The withdrawal that was cancelled.
-/// * `event_data` - The event log data.
-fn after_withdrawal_cancellation(
- key: felt252,
- withdrawal: Withdrawal,
- event_data: EventLogData,
- event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_withdrawal_cancellation(key: felt252, withdrawal: Withdrawal, mut log_data: LogData) {
if !is_valid_callback_contract(withdrawal.callback_contract) {
return;
}
let dispatcher = IWithdrawalCallbackReceiverDispatcher {
contract_address: withdrawal.callback_contract
};
- dispatcher.after_withdrawal_cancellation(key, withdrawal, event_data)
+ dispatcher.after_withdrawal_cancellation(key, withdrawal, log_data.serialize_into())
}
/// Called after an order execution.
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was executed.
-/// * `event_data` - The event log data.
-fn after_order_execution(
- key: felt252, order: Order, event_data: EventLogData, event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_order_execution(key: felt252, order: Order, mut log_data: LogData) {
if !is_valid_callback_contract(order.callback_contract) {
return;
}
let dispatcher = IOrderCallbackReceiverDispatcher { contract_address: order.callback_contract };
- dispatcher.after_order_execution(key, order, event_data)
+ dispatcher.after_order_execution(key, order, log_data.serialize_into())
}
/// Called after an order cancellation.
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was cancelled.
-/// * `event_data` - The event log data.
-fn after_order_cancellation(
- key: felt252, order: Order, event_data: EventLogData, event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_order_cancellation(key: felt252, order: Order, mut log_data: LogData) {
if !is_valid_callback_contract(order.callback_contract) {
return;
}
let dispatcher = IOrderCallbackReceiverDispatcher { contract_address: order.callback_contract };
- dispatcher.after_order_cancellation(key, order, event_data)
+ dispatcher.after_order_cancellation(key, order, log_data.serialize_into())
}
/// Called after an order cancellation.
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was frozen.
-/// * `event_data` - The event log data.
-fn after_order_frozen(
- key: felt252, order: Order, event_data: EventLogData, event_emitter: IEventEmitterDispatcher
-) {
+/// * `log_data` - The log data.
+fn after_order_frozen(key: felt252, order: Order, mut log_data: LogData) {
if !is_valid_callback_contract(order.callback_contract) {
return;
}
let dispatcher = IOrderCallbackReceiverDispatcher { contract_address: order.callback_contract };
- dispatcher.after_order_frozen(key, order, event_data)
+ dispatcher.after_order_frozen(key, order, log_data.serialize_into())
}
/// Validates that the given address is a contract.
diff --git a/src/callback/deposit_callback_receiver/interface.cairo b/src/callback/deposit_callback_receiver/interface.cairo
index 19f933fa..e45b7b33 100644
--- a/src/callback/deposit_callback_receiver/interface.cairo
+++ b/src/callback/deposit_callback_receiver/interface.cairo
@@ -1,6 +1,6 @@
// Satoru imports
use satoru::deposit::deposit::Deposit;
-use satoru::event::event_utils::EventLogData;
+use satoru::event::event_utils::LogData;
// *************************************************************************
// Interface of the `DepositCallbackReceiver` contract.
@@ -13,7 +13,7 @@ trait IDepositCallbackReceiver {
/// * `event_data` - The event log data.
/// * `deposit` - The deposit that was executed.
fn after_deposit_execution(
- ref self: TContractState, key: felt252, deposit: Deposit, event_data: EventLogData,
+ ref self: TContractState, key: felt252, deposit: Deposit, log_data: Array,
);
/// Called after a deposit cancellation.
@@ -22,6 +22,6 @@ trait IDepositCallbackReceiver {
/// * `event_data` - The event log data.
/// * `deposit` - The deposit that was cancelled.
fn after_deposit_cancellation(
- ref self: TContractState, key: felt252, deposit: Deposit, event_data: EventLogData,
+ ref self: TContractState, key: felt252, deposit: Deposit, log_data: Array,
);
}
diff --git a/src/callback/mocks.cairo b/src/callback/mocks.cairo
index 6f01cbce..a8457361 100644
--- a/src/callback/mocks.cairo
+++ b/src/callback/mocks.cairo
@@ -1,7 +1,7 @@
use starknet::ContractAddress;
use snforge_std::{declare, ContractClassTrait};
-use satoru::tests_lib::{setup, teardown, deploy_event_emitter};
+use satoru::test_utils::tests_lib::{setup, teardown, deploy_event_emitter};
#[starknet::interface]
trait ICallbackMock {
@@ -12,7 +12,7 @@ trait ICallbackMock {
mod CallbackMock {
use satoru::callback::deposit_callback_receiver::interface::IDepositCallbackReceiver;
use satoru::deposit::deposit::Deposit;
- use satoru::event::event_utils::EventLogData;
+ use satoru::event::event_utils::LogData;
#[storage]
struct Storage {
@@ -25,23 +25,23 @@ mod CallbackMock {
}
- #[external(v0)]
+ #[abi(embed_v0)]
impl ICallbackMockImpl of super::ICallbackMock {
fn get_counter(self: @ContractState) -> u32 {
self.counter.read()
}
}
- #[external(v0)]
+ #[abi(embed_v0)]
impl IDepositCallbackReceiverImpl of IDepositCallbackReceiver {
fn after_deposit_execution(
- ref self: ContractState, key: felt252, deposit: Deposit, event_data: EventLogData,
+ ref self: ContractState, key: felt252, deposit: Deposit, log_data: Array,
) {
self.counter.write(self.get_counter() + 1);
}
fn after_deposit_cancellation(
- ref self: ContractState, key: felt252, deposit: Deposit, event_data: EventLogData,
+ ref self: ContractState, key: felt252, deposit: Deposit, log_data: Array,
) {
self.counter.write(self.get_counter() + 1);
}
diff --git a/src/callback/order_callback_receiver/interface.cairo b/src/callback/order_callback_receiver/interface.cairo
index 29d5b255..8d1c8912 100644
--- a/src/callback/order_callback_receiver/interface.cairo
+++ b/src/callback/order_callback_receiver/interface.cairo
@@ -1,6 +1,6 @@
// Satoru imports
use satoru::order::order::Order;
-use satoru::event::event_utils::EventLogData;
+use satoru::event::event_utils::LogData;
// *************************************************************************
// Interface of the `OrderCallbackReceiver` contract.
@@ -11,26 +11,26 @@ trait IOrderCallbackReceiver {
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was executed.
- /// * `event_data` - The event log data.
+ /// * `log_data` - The log data.
fn after_order_execution(
- ref self: TContractState, key: felt252, order: Order, event_data: EventLogData
+ ref self: TContractState, key: felt252, order: Order, log_data: Array
);
/// Called after an order cancellation.
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was cancelled.
- /// * `event_data` - The event log data.
+ /// * `log_data` - The log data.
fn after_order_cancellation(
- ref self: TContractState, key: felt252, order: Order, event_data: EventLogData
+ ref self: TContractState, key: felt252, order: Order, log_data: Array
);
/// Called after an order cancellation.
/// # Arguments
/// * `key` - They key of the order.
/// * `order` - The order that was frozen.
- /// * `event_data` - The event log data.
+ /// * `log_data` - The log data.
fn after_order_frozen(
- ref self: TContractState, key: felt252, order: Order, event_data: EventLogData
+ ref self: TContractState, key: felt252, order: Order, log_data: Array
);
}
diff --git a/src/callback/withdrawal_callback_receiver/interface.cairo b/src/callback/withdrawal_callback_receiver/interface.cairo
index 146f88bb..1c43a31f 100644
--- a/src/callback/withdrawal_callback_receiver/interface.cairo
+++ b/src/callback/withdrawal_callback_receiver/interface.cairo
@@ -1,6 +1,6 @@
// Satoru imports
use satoru::withdrawal::withdrawal::Withdrawal;
-use satoru::event::event_utils::EventLogData;
+use satoru::event::event_utils::LogData;
// *************************************************************************
// Interface of the `WithdrawalCallbackReceiver` contract.
@@ -11,18 +11,18 @@ trait IWithdrawalCallbackReceiver {
/// # Arguments
/// * `key` - They key of the withdrawal.
/// * `withdrawal` - The withdrawal that was executed.
- /// * `event_data` - The event log data.
+ /// * `log_data` - The log data.
// TODO uncomment withdrawal when available
fn after_withdrawal_execution(
- ref self: TContractState, key: felt252, withdrawal: Withdrawal, event_data: EventLogData,
+ ref self: TContractState, key: felt252, withdrawal: Withdrawal, log_data: Array,
);
/// Called after an withdrawal cancellation.
/// # Arguments
/// * `key` - They key of the withdrawal.
/// * `withdrawal` - The withdrawal that was cancelled.
- /// * `event_data` - The event log data.
+ /// * `log_data` - The log data.
fn after_withdrawal_cancellation(
- ref self: TContractState, key: felt252, withdrawal: Withdrawal, event_data: EventLogData,
+ ref self: TContractState, key: felt252, withdrawal: Withdrawal, log_data: Array,
);
}
diff --git a/src/chain/chain.cairo b/src/chain/chain.cairo
index d860dbc9..5f5ed9d0 100644
--- a/src/chain/chain.cairo
+++ b/src/chain/chain.cairo
@@ -28,7 +28,7 @@ mod Chain {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl Chain of super::IChain {
fn get_block_number(self: @ContractState) -> u64 {
starknet::info::get_block_number()
diff --git a/src/config/config.cairo b/src/config/config.cairo
index 8ae72cfd..ca822651 100644
--- a/src/config/config.cairo
+++ b/src/config/config.cairo
@@ -48,7 +48,6 @@ mod Config {
use starknet::{get_caller_address, ContractAddress, contract_address_const,};
use poseidon::poseidon_hash_span;
- use debug::PrintTrait;
// Local imports.
use satoru::role::role;
@@ -98,7 +97,7 @@ mod Config {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl ConfigImpl of super::IConfig {
fn set_bool(
ref self: ContractState, base_key: felt252, data: Array, value: bool,
diff --git a/src/config/timelock.cairo b/src/config/timelock.cairo
index 9016ab11..05117a19 100644
--- a/src/config/timelock.cairo
+++ b/src/config/timelock.cairo
@@ -24,7 +24,6 @@ mod Timelock {
use core::zeroable::Zeroable;
use starknet::{get_caller_address, ContractAddress, contract_address_const};
- use debug::PrintTrait;
// Local imports.
@@ -46,6 +45,6 @@ mod Timelock {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl TimelockImpl of super::ITimelock {}
}
diff --git a/src/data/data_store.cairo b/src/data/data_store.cairo
index cd519245..995409a7 100644
--- a/src/data/data_store.cairo
+++ b/src/data/data_store.cairo
@@ -10,12 +10,40 @@ use satoru::order::order::Order;
use satoru::position::position::Position;
use satoru::withdrawal::withdrawal::Withdrawal;
use satoru::deposit::deposit::Deposit;
+use satoru::utils::i256::i256;
// *************************************************************************
// Interface of the `DataStore` contract.
// *************************************************************************
#[starknet::interface]
trait IDataStore {
+ fn get_max_pool_amount_key(
+ self: @TContractState, market_token: ContractAddress, token: ContractAddress
+ ) -> felt252;
+ fn get_open_interest_key(
+ self: @TContractState,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool
+ ) -> felt252;
+ fn get_max_open_interest_key(
+ self: @TContractState, market: ContractAddress, is_long: bool
+ ) -> felt252;
+ fn get_pool_amount_key(
+ self: @TContractState, market: ContractAddress, token: ContractAddress
+ ) -> felt252;
+ fn get_max_pnl_factor_key(
+ self: @TContractState, pnl_factor_type: felt252, market: ContractAddress, is_long: bool
+ ) -> felt252;
+ fn get_max_pnl_factor_for_deposit_key(self: @TContractState) -> felt252;
+ fn get_max_pnl_factor_for_withdrawals_key(self: @TContractState) -> felt252;
+ fn get_reserve_factor_key(
+ self: @TContractState, market: ContractAddress, is_long: bool
+ ) -> felt252;
+ fn get_open_interest_reserve_factor_key(
+ self: @TContractState, market: ContractAddress, is_long: bool
+ ) -> felt252;
+
// *************************************************************************
// Felt252 related functions.
// *************************************************************************
@@ -82,39 +110,21 @@ trait IDataStore {
/// * `value` - The value to subtract.
fn decrement_u256(ref self: TContractState, key: felt252, value: u256) -> u256;
-
- // *************************************************************************
- // u128 related functions.
- // *************************************************************************
- /// Get a u128 value for the given key.
- /// # Arguments
- /// * `key` - The key to get the value for.
- /// # Returns
- /// The value for the given key.
- fn get_u128(self: @TContractState, key: felt252) -> u128;
-
- /// Set a u128 value for the given key.
- /// # Arguments
- /// * `key` - The key to set the value for.
- /// * `value` - The value to set.
- fn set_u128(ref self: TContractState, key: felt252, value: u128);
-
- /// Delete a u128 value for the given key.
- /// # Arguments
- /// * `key` - The key to delete the value for.
- fn remove_u128(ref self: TContractState, key: felt252);
-
- /// Add input to existing value.
+ /// Add signed value to existing value if result positive.
/// # Arguments
/// * `key` - The key to add the value to.
/// * `value` - The value to add.
- fn increment_u128(ref self: TContractState, key: felt252, value: u128) -> u128;
+ /// * `error` - The error to throw if result is negative.
+ fn apply_delta_to_u256(
+ ref self: TContractState, key: felt252, value: i256, error: felt252
+ ) -> u256;
- /// Subtract input from existing value.
+ /// Add the input int value to the existing uint value, prevent the uint
+ /// value from becoming negative
/// # Arguments
- /// * `key` - The key to subtract the value from.
- /// * `value` - The value to subtract.
- fn decrement_u128(ref self: TContractState, key: felt252, value: u128) -> u128;
+ /// * `key` - the key of the value
+ /// * `value` - the input int value
+ fn apply_bounded_delta_to_u256(ref self: TContractState, key: felt252, value: i256) -> u256;
// *************************************************************************
// Address related functions.
@@ -144,7 +154,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_bool(self: @TContractState, key: felt252) -> Option;
+ fn get_bool(self: @TContractState, key: felt252) -> bool;
/// Set a bool value for the given key.
/// # Arguments
@@ -165,7 +175,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_market(self: @TContractState, key: ContractAddress) -> Option;
+ fn get_market(self: @TContractState, key: ContractAddress) -> Market;
/// Set a market value for the given key.
/// # Arguments
@@ -177,7 +187,7 @@ trait IDataStore {
/// * `salt` - The salt to get the value for.
/// # Returns
/// The value for the given key.
- fn get_by_salt_market(self: @TContractState, salt: felt252) -> Option;
+ fn get_by_salt_market(self: @TContractState, salt: felt252) -> Market;
fn remove_market(ref self: TContractState, key: ContractAddress);
/// Get a hash given salt.
/// # Arguments
@@ -222,7 +232,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_order(self: @TContractState, key: felt252) -> Option;
+ fn get_order(self: @TContractState, key: felt252) -> Order;
/// Set a order value for the given key.
/// # Arguments
@@ -243,7 +253,6 @@ trait IDataStore {
/// * `end` - Start index
fn get_order_keys(self: @TContractState, start: usize, end: usize) -> Array;
- // TODO checkk
/// Return total order count
fn get_order_count(self: @TContractState) -> u32;
@@ -273,7 +282,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_position(self: @TContractState, key: felt252) -> Option;
+ fn get_position(self: @TContractState, key: felt252) -> Position;
/// Set a position value for the given key.
/// # Arguments
@@ -294,7 +303,6 @@ trait IDataStore {
/// * `end` - Start index
fn get_position_keys(self: @TContractState, start: usize, end: usize) -> Array;
- // TODO checkk
/// Return total position count
fn get_position_count(self: @TContractState) -> u32;
@@ -323,7 +331,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_withdrawal(self: @TContractState, key: felt252) -> Option;
+ fn get_withdrawal(self: @TContractState, key: felt252) -> Withdrawal;
/// Set a withdrawal value for the given key.
/// # Arguments
@@ -374,7 +382,7 @@ trait IDataStore {
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_deposit(self: @TContractState, key: felt252) -> Option;
+ fn get_deposit(self: @TContractState, key: felt252) -> Deposit;
/// Set a deposit value for the given key.
/// # Arguments
@@ -411,16 +419,15 @@ trait IDataStore {
) -> Array;
- //TODO: Update u128 to i128 when Serde and Store for i128 implementations are released.
// *************************************************************************
- // int128 related functions.
+ // int256 related functions.
// *************************************************************************
/// Get a int value for the given key.
/// # Arguments
/// * `key` - The key to get the value for.
/// # Returns
/// The value for the given key.
- fn get_i128(self: @TContractState, key: felt252) -> u128;
+ fn get_i256(self: @TContractState, key: felt252) -> i256;
/// Set the int value for the given key.
/// # Arguments
@@ -428,25 +435,31 @@ trait IDataStore {
/// `value` - The value to set
/// # Return
/// The int value for the key.
- fn set_i128(ref self: TContractState, key: felt252, value: u128);
+ fn set_i256(ref self: TContractState, key: felt252, value: i256);
- /// Delete a i128 value for the given key.
+ /// Delete a i256 value for the given key.
/// # Arguments
/// * `key` - The key to delete the value for.
- fn remove_i128(ref self: TContractState, key: felt252);
+ fn remove_i256(ref self: TContractState, key: felt252);
+
+ // @dev add the input int value to the existing int value
+ // @param key the key of the value
+ // @param value the input int value
+ // @return the new int value
+ fn apply_delta_to_i256(ref self: TContractState, key: felt252, value: i256) -> i256;
/// Add input to existing value.
/// # Arguments
/// * `key` - The key to add the value to.
/// * `value` - The value to add.
- fn increment_i128(ref self: TContractState, key: felt252, value: u128) -> u128;
+ fn increment_i256(ref self: TContractState, key: felt252, value: i256) -> i256;
/// Subtract input from existing value.
/// # Arguments
/// * `key` - The key to subtract the value from.
/// * `value` - The value to subtract.
- fn decrement_i128(ref self: TContractState, key: felt252, value: u128) -> u128;
+ fn decrement_i256(ref self: TContractState, key: felt252, value: i256) -> i256;
}
#[starknet::contract]
@@ -458,14 +471,14 @@ mod DataStore {
// Core lib imports.
use core::option::OptionTrait;
use core::traits::TryInto;
- use starknet::{get_caller_address, ContractAddress, contract_address_const,};
+ use starknet::{get_caller_address, ContractAddress, contract_address_const};
use nullable::NullableTrait;
use zeroable::Zeroable;
use alexandria_storage::list::{ListTrait, List};
- use debug::PrintTrait;
use poseidon::poseidon_hash_span;
// Local imports.
+ use satoru::data::keys;
use satoru::role::role;
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
use satoru::market::{market::{Market, ValidateMarket}, error::MarketError};
@@ -474,6 +487,9 @@ mod DataStore {
use satoru::position::{position::Position, error::PositionError};
use satoru::withdrawal::{withdrawal::Withdrawal, error::WithdrawalError};
use satoru::deposit::{deposit::Deposit, error::DepositError};
+ use satoru::utils::calc::{sum_return_uint_256, to_signed, to_unsigned};
+ use satoru::utils::calc;
+ use satoru::utils::i256::{i256, i256_neg};
// *************************************************************************
// STORAGE
@@ -483,10 +499,9 @@ mod DataStore {
role_store: IRoleStoreDispatcher,
felt252_values: LegacyMap::,
u256_values: LegacyMap::,
- u128_values: LegacyMap::,
- i128_values: LegacyMap::,
+ i256_values: LegacyMap::,
address_values: LegacyMap::,
- bool_values: LegacyMap::>,
+ bool_values: LegacyMap::,
/// Market storage
market_values: LegacyMap::,
markets: List,
@@ -525,8 +540,61 @@ mod DataStore {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl DataStore of super::IDataStore {
+ fn get_max_pool_amount_key(
+ self: @ContractState, market_token: ContractAddress, token: ContractAddress
+ ) -> felt252 {
+ keys::max_pool_amount_key(market_token, token)
+ }
+
+ fn get_open_interest_key(
+ self: @ContractState,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool
+ ) -> felt252 {
+ keys::open_interest_key(market, collateral_token, is_long)
+ }
+
+ fn get_max_open_interest_key(
+ self: @ContractState, market: ContractAddress, is_long: bool
+ ) -> felt252 {
+ keys::max_open_interest_key(market, is_long)
+ }
+
+ fn get_pool_amount_key(
+ self: @ContractState, market: ContractAddress, token: ContractAddress
+ ) -> felt252 {
+ keys::pool_amount_key(market, token)
+ }
+
+ fn get_max_pnl_factor_key(
+ self: @ContractState, pnl_factor_type: felt252, market: ContractAddress, is_long: bool
+ ) -> felt252 {
+ keys::max_pnl_factor_key(pnl_factor_type, market, is_long)
+ }
+
+ fn get_max_pnl_factor_for_deposit_key(self: @ContractState) -> felt252 {
+ keys::max_pnl_factor_for_deposits()
+ }
+
+ fn get_max_pnl_factor_for_withdrawals_key(self: @ContractState) -> felt252 {
+ keys::max_pnl_factor_for_withdrawals()
+ }
+
+ fn get_reserve_factor_key(
+ self: @ContractState, market: ContractAddress, is_long: bool
+ ) -> felt252 {
+ keys::reserve_factor_key(market, is_long)
+ }
+
+ fn get_open_interest_reserve_factor_key(
+ self: @ContractState, market: ContractAddress, is_long: bool
+ ) -> felt252 {
+ keys::open_interest_reserve_factor_key(market, is_long)
+ }
+
// *************************************************************************
// Felt252 related functions.
// *************************************************************************
@@ -622,98 +690,82 @@ mod DataStore {
new_value
}
- // *************************************************************************
- // u128 related functions.
- // *************************************************************************
- fn get_u128(self: @ContractState, key: felt252) -> u128 {
- self.u128_values.read(key)
- }
-
- fn set_u128(ref self: ContractState, key: felt252, value: u128) {
+ fn apply_delta_to_u256(
+ ref self: ContractState, key: felt252, value: i256, error: felt252
+ ) -> u256 {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- // Set the value.
- self.u128_values.write(key, value);
- }
- fn remove_u128(ref self: ContractState, key: felt252) {
- // Check that the caller has permission to delete the value.
- self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- // Delete the value.
- self.u128_values.write(key, Default::default());
- }
-
- fn increment_u128(ref self: ContractState, key: felt252, value: u128) -> u128 {
- // Check that the caller has permission to set the value.
- self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- // Get the current value.
- let current_value = self.u128_values.read(key);
- // Add the delta to the current value.
- let new_value = current_value + value;
- // Set the new value.
- self.u128_values.write(key, new_value);
- // Return the new value.
- new_value
+ let current_value = self.u256_values.read(key);
+ if value < Zeroable::zero() && calc::to_unsigned(i256_neg(value)) > current_value {
+ panic(array![error]);
+ }
+ let next_value = calc::sum_return_uint_256(current_value, value);
+ self.u256_values.write(key, next_value);
+ next_value
}
- fn decrement_u128(ref self: ContractState, key: felt252, value: u128) -> u128 {
- // Check that the caller has permission to set the value.
- self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- // Get the current value.
- let current_value = self.u128_values.read(key);
- // Subtract the delta from the current value.
- let new_value = current_value - value;
- // Set the new value.
- self.u128_values.write(key, new_value);
- // Return the new value.
- new_value
+ fn apply_bounded_delta_to_u256(ref self: ContractState, key: felt252, value: i256) -> u256 {
+ let uint_value: u256 = self.u256_values.read(key);
+ if (value < Zeroable::zero() && to_unsigned(i256_neg(value)) > uint_value) {
+ self.u256_values.write(key, 0);
+ return 0;
+ }
+ let next_uint: u256 = sum_return_uint_256(uint_value, value);
+ self.u256_values.write(key, next_uint);
+ next_uint
}
- //TODO: Update u128 to i128 when Serde and Store for i128 implementations are released.
// *************************************************************************
- // i128 related functions.
+ // i256 related functions.
// *************************************************************************
- fn get_i128(self: @ContractState, key: felt252) -> u128 {
- self.i128_values.read(key)
+ fn get_i256(self: @ContractState, key: felt252) -> i256 {
+ self.i256_values.read(key)
}
- fn set_i128(ref self: ContractState, key: felt252, value: u128) {
+ fn set_i256(ref self: ContractState, key: felt252, value: i256) {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Set the value.
- self.i128_values.write(key, value);
+ self.i256_values.write(key, value);
}
- fn remove_i128(ref self: ContractState, key: felt252) {
+ fn remove_i256(ref self: ContractState, key: felt252) {
// Check that the caller has permission to delete the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Delete the value.
- self.i128_values.write(key, Default::default());
+ self.i256_values.write(key, Default::default());
+ }
+
+ fn apply_delta_to_i256(ref self: ContractState, key: felt252, value: i256) -> i256 {
+ let next_int: i256 = self.i256_values.read(key) + value;
+ self.i256_values.write(key, next_int);
+ next_int
}
- fn increment_i128(ref self: ContractState, key: felt252, value: u128) -> u128 {
+ fn increment_i256(ref self: ContractState, key: felt252, value: i256) -> i256 {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Get the current value.
- let current_value = self.i128_values.read(key);
+ let current_value = self.i256_values.read(key);
// Add the delta to the current value.
// TODO: Check for overflow.
let new_value = current_value + value;
// Set the new value.
- self.i128_values.write(key, new_value);
+ self.i256_values.write(key, new_value);
// Return the new value.
new_value
}
- fn decrement_i128(ref self: ContractState, key: felt252, value: u128) -> u128 {
+ fn decrement_i256(ref self: ContractState, key: felt252, value: i256) -> i256 {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Get the current value.
- let current_value = self.i128_values.read(key);
+ let current_value = self.i256_values.read(key);
// Subtract the delta from the current value.
let new_value = current_value - value;
// Set the new value.
- self.i128_values.write(key, new_value);
+ self.i256_values.write(key, new_value);
// Return the new value.
new_value
}
@@ -742,7 +794,7 @@ mod DataStore {
// *************************************************************************
// Bool related functions.
// *************************************************************************
- fn get_bool(self: @ContractState, key: felt252) -> Option {
+ fn get_bool(self: @ContractState, key: felt252) -> bool {
self.bool_values.read(key)
}
@@ -750,27 +802,31 @@ mod DataStore {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Set the value.
- self.bool_values.write(key, Option::Some(value));
+ self.bool_values.write(key, value);
}
fn remove_bool(ref self: ContractState, key: felt252) {
// Check that the caller has permission to delete the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
// Delete the value.
- self.bool_values.write(key, Option::None);
+ self.bool_values.write(key, false);
}
// *************************************************************************
// Market related functions.
// *************************************************************************
- fn get_market(self: @ContractState, key: ContractAddress) -> Option {
+ fn get_market(self: @ContractState, key: ContractAddress) -> Market {
let offsetted_index: usize = self.market_indexes.read(key);
if offsetted_index == 0 {
- return Option::None;
+ return Default::default();
+ }
+ let markets: List = self.markets.read();
+ let market_maybe = markets.get(offsetted_index - 1);
+ match market_maybe {
+ Option::Some(market) => { market },
+ Option::None => { Default::default() }
}
- let orders: List = self.markets.read();
- orders.get(offsetted_index - 1)
}
fn set_market(
@@ -804,7 +860,10 @@ mod DataStore {
self.role_store.read().assert_only_role(get_caller_address(), role::MARKET_KEEPER);
let offsetted_index: usize = self.market_indexes.read(key);
let mut markets = self.markets.read();
- assert(offsetted_index <= markets.len(), MarketError::MARKET_NOT_FOUND);
+ assert(
+ offsetted_index != 0 && offsetted_index <= markets.len(),
+ MarketError::MARKET_NOT_FOUND
+ );
let index = offsetted_index - 1;
// Replace the value at `index` by the last market in the list.
@@ -860,7 +919,7 @@ mod DataStore {
self.markets.read().len()
}
- fn get_by_salt_market(self: @ContractState, salt: felt252) -> Option {
+ fn get_by_salt_market(self: @ContractState, salt: felt252) -> Market {
let key = self.get_address(self.get_market_salt_hash(salt));
self.get_market(key)
}
@@ -885,19 +944,23 @@ mod DataStore {
// Order related functions.
// *************************************************************************
- fn get_order(self: @ContractState, key: felt252) -> Option {
+ fn get_order(self: @ContractState, key: felt252) -> Order {
let offsetted_index: usize = self.order_indexes.read(key);
if offsetted_index == 0 {
- return Option::None;
+ return Default::default();
}
let orders: List = self.orders.read();
- orders.get(offsetted_index - 1)
+ let order_maybe = orders.get(offsetted_index - 1);
+ match order_maybe {
+ Option::Some(order) => { order },
+ Option::None => { Default::default() }
+ }
}
fn set_order(ref self: ContractState, key: felt252, order: Order) {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- assert(order.account != 0.try_into().unwrap(), OrderError::CANT_BE_ZERO);
+ assert(order.account != contract_address_const::<0>(), OrderError::CANT_BE_ZERO);
let mut orders = self.orders.read();
let mut account_orders = self.account_orders.read(order.account);
@@ -925,7 +988,9 @@ mod DataStore {
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
let offsetted_index: usize = self.order_indexes.read(key);
let mut orders = self.orders.read();
- assert(offsetted_index <= orders.len(), OrderError::ORDER_NOT_FOUND);
+ assert(
+ offsetted_index != 0 && offsetted_index <= orders.len(), OrderError::ORDER_NOT_FOUND
+ );
let index = offsetted_index - 1;
// Replace the value at `index` by the last order in the list.
@@ -1016,19 +1081,23 @@ mod DataStore {
// Position related functions.
// *************************************************************************
- fn get_position(self: @ContractState, key: felt252) -> Option {
+ fn get_position(self: @ContractState, key: felt252) -> Position {
let offsetted_index: usize = self.position_indexes.read(key);
if offsetted_index == 0 {
- return Option::None;
+ return Default::default();
}
let positions: List = self.positions.read();
- positions.get(offsetted_index - 1)
+ let position_maybe = positions.get(offsetted_index - 1);
+ match position_maybe {
+ Option::Some(position) => { position },
+ Option::None => { Default::default() }
+ }
}
fn set_position(ref self: ContractState, key: felt252, position: Position) {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- assert(position.account != 0.try_into().unwrap(), PositionError::CANT_BE_ZERO);
+ assert(position.account != contract_address_const::<0>(), PositionError::CANT_BE_ZERO);
let mut positions = self.positions.read();
let mut account_positions = self.account_positions.read(position.account);
@@ -1056,7 +1125,10 @@ mod DataStore {
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
let offsetted_index: usize = self.position_indexes.read(key);
let mut positions = self.positions.read();
- assert(offsetted_index <= positions.len(), PositionError::POSITION_NOT_FOUND);
+ assert(
+ offsetted_index != 0 && offsetted_index <= positions.len(),
+ PositionError::POSITION_NOT_FOUND
+ );
let index = offsetted_index - 1;
// Replace the value at `index` by the last position in the list.
@@ -1147,19 +1219,25 @@ mod DataStore {
// Withdrawal related functions.
// *************************************************************************
- fn get_withdrawal(self: @ContractState, key: felt252) -> Option {
+ fn get_withdrawal(self: @ContractState, key: felt252) -> Withdrawal {
let offsetted_index: usize = self.withdrawal_indexes.read(key);
if offsetted_index == 0 {
- return Option::None;
+ return Default::default();
}
let withdrawals: List = self.withdrawals.read();
- withdrawals.get(offsetted_index - 1)
+ let withdrawal_maybe = withdrawals.get(offsetted_index - 1);
+ match withdrawal_maybe {
+ Option::Some(withdrawal) => { withdrawal },
+ Option::None => { Default::default() }
+ }
}
fn set_withdrawal(ref self: ContractState, key: felt252, withdrawal: Withdrawal) {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- assert(withdrawal.account != 0.try_into().unwrap(), WithdrawalError::CANT_BE_ZERO);
+ assert(
+ withdrawal.account != contract_address_const::<0>(), WithdrawalError::CANT_BE_ZERO
+ );
let mut withdrawals = self.withdrawals.read();
let mut account_withdrawals = self.account_withdrawals.read(withdrawal.account);
@@ -1187,7 +1265,10 @@ mod DataStore {
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
let offsetted_index: usize = self.withdrawal_indexes.read(key);
let mut withdrawals = self.withdrawals.read();
- assert(offsetted_index <= withdrawals.len(), WithdrawalError::NOT_FOUND);
+ assert(
+ offsetted_index != 0 && offsetted_index <= withdrawals.len(),
+ WithdrawalError::NOT_FOUND
+ );
let index = offsetted_index - 1;
// Replace the value at `index` by the last withdrawal in the list.
@@ -1274,19 +1355,23 @@ mod DataStore {
// Deposit related functions.
// *************************************************************************
- fn get_deposit(self: @ContractState, key: felt252) -> Option {
+ fn get_deposit(self: @ContractState, key: felt252) -> Deposit {
let offsetted_index: usize = self.deposit_indexes.read(key);
if offsetted_index == 0 {
- return Option::None;
+ return Default::default();
}
let deposits: List = self.deposits.read();
- deposits.get(offsetted_index - 1)
+ let deposit_maybe = deposits.get(offsetted_index - 1);
+ match deposit_maybe {
+ Option::Some(deposit) => { deposit },
+ Option::None => { Default::default() }
+ }
}
fn set_deposit(ref self: ContractState, key: felt252, deposit: Deposit) {
// Check that the caller has permission to set the value.
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
- assert(deposit.account != 0.try_into().unwrap(), DepositError::CANT_BE_ZERO);
+ assert(deposit.account != contract_address_const::<0>(), DepositError::CANT_BE_ZERO);
let mut deposits = self.deposits.read();
let mut account_deposits = self.account_deposits.read(deposit.account);
@@ -1313,7 +1398,10 @@ mod DataStore {
self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
let offsetted_index: usize = self.deposit_indexes.read(key);
let mut deposits = self.deposits.read();
- assert(offsetted_index <= deposits.len(), DepositError::DEPOSIT_NOT_FOUND);
+ assert(
+ offsetted_index != 0 && offsetted_index <= deposits.len(),
+ DepositError::DEPOSIT_NOT_FOUND
+ );
let index = offsetted_index - 1;
// Replace the value at `index` by the last deposit in the list.
@@ -1421,6 +1509,9 @@ mod DataStore {
if account_withdrawals.len() == 0 {
break;
}
+ if last_key == withdrawal_key {
+ break;
+ }
account_withdrawals.set(i, last_key);
},
Option::None => {
@@ -1450,6 +1541,9 @@ mod DataStore {
if account_orders.len() == 0 {
break;
}
+ if last_key == order_key {
+ break;
+ }
account_orders.set(i, last_key);
},
Option::None => {
@@ -1481,6 +1575,9 @@ mod DataStore {
if account_deposits.len() == 0 {
break;
}
+ if last_key == deposit_key {
+ break;
+ }
account_deposits.set(i, last_key);
},
Option::None => {
@@ -1512,6 +1609,9 @@ mod DataStore {
if account_positions.len() == 0 {
break;
}
+ if last_key == position_key {
+ break;
+ }
account_positions.set(i, last_key);
},
Option::None => {
diff --git a/src/data/error.cairo b/src/data/error.cairo
index b611bc06..e6365f3a 100644
--- a/src/data/error.cairo
+++ b/src/data/error.cairo
@@ -1,4 +1,5 @@
mod DataError {
const MARKET_NOT_FOUND: felt252 = 'market_not_found';
const MARKET_INDEX_NOT_FOUND: felt252 = 'market_index_not_found';
+ const POSITION_NOT_FOUND: felt252 = 'position_not_found';
}
diff --git a/src/data/keys.cairo b/src/data/keys.cairo
index 6457a260..d47b81b3 100644
--- a/src/data/keys.cairo
+++ b/src/data/keys.cairo
@@ -694,7 +694,7 @@ fn account_order_list_key(account: ContractAddress) -> felt252 {
/// * `token` - The token for the fee.
/// # Returns
/// * The key for the claimable fee amount.
-fn claim_fee_amount_key(market: ContractAddress, token: ContractAddress) -> felt252 {
+fn claimable_fee_amount_key(market: ContractAddress, token: ContractAddress) -> felt252 {
let mut data = array![];
data.append(claimable_fee_amount());
data.append(market.into());
@@ -709,7 +709,7 @@ fn claim_fee_amount_key(market: ContractAddress, token: ContractAddress) -> felt
/// * `account` - The account that can claim the ui fee.
/// # Returns
/// * The key for the claimable ui fee amount.
-fn claim_ui_fee_amount_key(market: ContractAddress, token: ContractAddress) -> felt252 {
+fn claimable_ui_fee_amount_key(market: ContractAddress, token: ContractAddress) -> felt252 {
let mut data = array![];
data.append(claimable_ui_fee_amount());
data.append(market.into());
@@ -724,7 +724,7 @@ fn claim_ui_fee_amount_key(market: ContractAddress, token: ContractAddress) -> f
/// * `account` - The account that can claim the ui fee.
/// # Returns
/// * The key for the claimable ui fee amount.
-fn claim_ui_fee_amount_for_account_key(
+fn claimable_ui_fee_amount_for_account_key(
market: ContractAddress, token: ContractAddress, account: ContractAddress
) -> felt252 {
let mut data = array![];
@@ -743,8 +743,7 @@ fn claim_ui_fee_amount_for_account_key(
fn deposit_gas_limit_key(single_token: bool) -> felt252 {
let mut data = array![];
data.append(deposit_gas_limit());
- // TODO: Replace by `single_token.into()` once upgrading to next version of Cairo.
- data.append(bool_to_felt252(single_token));
+ data.append(single_token.into());
poseidon_hash_span(data.span())
}
@@ -1447,13 +1446,13 @@ fn claimable_collateral_amount_key(market: ContractAddress, token: ContractAddre
/// * `time_key` - The time key for the claimable amount.
/// * `account` - The account address.
fn claimable_collateral_amount_for_account_key(
- market: ContractAddress, token: ContractAddress, time_key: u128, account: ContractAddress
+ market: ContractAddress, token: ContractAddress, time_key: u256, account: ContractAddress
) -> felt252 {
let mut data = array![];
data.append(claimable_collateral_amount());
data.append(market.into());
data.append(token.into());
- data.append(time_key.into());
+ data.append(time_key.try_into().expect('u256 into felt failed'));
data.append(account.into());
poseidon_hash_span(data.span())
}
@@ -1464,13 +1463,13 @@ fn claimable_collateral_amount_for_account_key(
/// * `token` - The token address.
/// * `time_key` - The time key for the claimable amount.
fn claimable_collateral_factor_key(
- market: ContractAddress, token: ContractAddress, time_key: felt252
+ market: ContractAddress, token: ContractAddress, time_key: u256
) -> felt252 {
let mut data = array![];
data.append(claimable_collateral_factor());
data.append(market.into());
data.append(token.into());
- data.append(time_key);
+ data.append(time_key.try_into().expect('u256 into felt failed'));
poseidon_hash_span(data.span())
}
@@ -1481,13 +1480,13 @@ fn claimable_collateral_factor_key(
/// * `time_key` - The time key for the claimable amount.
/// * `account` - The account address.
fn claimable_collateral_factor_for_account_key(
- market: ContractAddress, token: ContractAddress, time_key: felt252, account: ContractAddress
+ market: ContractAddress, token: ContractAddress, time_key: u256, account: ContractAddress
) -> felt252 {
let mut data = array![];
data.append(claimable_collateral_factor());
data.append(market.into());
data.append(token.into());
- data.append(time_key);
+ data.append(time_key.try_into().expect('u256 into felt failed'));
data.append(account.into());
poseidon_hash_span(data.span())
}
@@ -1499,13 +1498,13 @@ fn claimable_collateral_factor_for_account_key(
/// * `time_key` - The time key for the claimable amount.
/// * `account` - The account address.
fn claimed_collateral_amount_key(
- market: ContractAddress, token: ContractAddress, time_key: felt252, account: ContractAddress
+ market: ContractAddress, token: ContractAddress, time_key: u256, account: ContractAddress
) -> felt252 {
let mut data = array![];
data.append(claimed_collateral_amount());
data.append(market.into());
data.append(token.into());
- data.append(time_key);
+ data.append(time_key.try_into().expect('u256 into felt failed'));
data.append(account.into());
poseidon_hash_span(data.span())
}
diff --git a/src/deposit/deposit.cairo b/src/deposit/deposit.cairo
index 114a3d16..bfb8b1fe 100644
--- a/src/deposit/deposit.cairo
+++ b/src/deposit/deposit.cairo
@@ -1,5 +1,5 @@
// Core Lib imports
-use starknet::ContractAddress;
+use starknet::{ContractAddress, contract_address_const};
// Satoru imports
use satoru::utils::store_arrays::StoreContractAddressArray;
@@ -29,31 +29,31 @@ struct Deposit {
/// The short token swap path.
short_token_swap_path: Span32,
/// The amount of long tokens to deposit.
- initial_long_token_amount: u128,
+ initial_long_token_amount: u256,
/// The amount of short tokens to deposit.
- initial_short_token_amount: u128,
+ initial_short_token_amount: u256,
/// The minimum acceptable number of liquidity tokens.
- min_market_tokens: u128,
+ min_market_tokens: u256,
/// The block that the deposit was last updated at sending funds back to the user in case the deposit gets cancelled.
updated_at_block: u64,
/// The execution fee for keepers.
- execution_fee: u128,
+ execution_fee: u256,
/// The gas limit for the callback contract.
/// TODO: investigate how we want to handle callback and gas limit for Starknet contracts.
- callback_gas_limit: u128,
+ callback_gas_limit: u256,
}
impl DefaultDeposit of Default {
fn default() -> Deposit {
Deposit {
key: 0,
- account: 0.try_into().unwrap(),
- receiver: 0.try_into().unwrap(),
- callback_contract: 0.try_into().unwrap(),
- ui_fee_receiver: 0.try_into().unwrap(),
- market: 0.try_into().unwrap(),
- initial_long_token: 0.try_into().unwrap(),
- initial_short_token: 0.try_into().unwrap(),
+ account: contract_address_const::<0>(),
+ receiver: contract_address_const::<0>(),
+ callback_contract: contract_address_const::<0>(),
+ ui_fee_receiver: contract_address_const::<0>(),
+ market: contract_address_const::<0>(),
+ initial_long_token: contract_address_const::<0>(),
+ initial_short_token: contract_address_const::<0>(),
long_token_swap_path: Array32Trait::::span32(@ArrayTrait::new()),
short_token_swap_path: Array32Trait::::span32(@ArrayTrait::new()),
initial_long_token_amount: 0,
diff --git a/src/deposit/deposit_utils.cairo b/src/deposit/deposit_utils.cairo
index 7e2b954c..8115fa03 100644
--- a/src/deposit/deposit_utils.cairo
+++ b/src/deposit/deposit_utils.cairo
@@ -8,6 +8,8 @@
use starknet::ContractAddress;
use starknet::info::get_block_number;
use result::ResultTrait;
+use satoru::utils::traits::ContractAddressDefault;
+use traits::Default;
// Local imports.
use satoru::utils::{
@@ -25,7 +27,7 @@ use satoru::callback::callback_utils::{validate_callback_gas_limit, after_deposi
use satoru::nonce::nonce_utils;
use satoru::token::token_utils;
use starknet::contract_address::ContractAddressZeroable;
-use satoru::event::event_utils::EventLogData;
+use satoru::event::event_utils::LogData;
/// Helps with deposit creation.
#[derive(Drop, starknet::Store, Serde)]
@@ -47,11 +49,11 @@ struct CreateDepositParams {
/// The swap path into markets for the short token.
short_token_swap_path: Span32,
/// The minimum acceptable number of liquidity tokens.
- min_market_tokens: u128,
+ min_market_tokens: u256,
/// The execution fee for keepers.
- execution_fee: u128,
+ execution_fee: u256,
/// The gas limit for the callback_contract.
- callback_gas_limit: u128,
+ callback_gas_limit: u256,
}
@@ -148,18 +150,14 @@ fn cancel_deposit(
deposit_vault: IDepositVaultDispatcher,
key: felt252,
keeper: ContractAddress,
- mut starting_gas: u128,
+ mut starting_gas: u256,
reason: felt252,
reason_bytes: Array
) {
starting_gas -= (starknet_utils::sn_gasleft(array![]) / 63);
// get deposit info from data_store
- let mut deposit = Default::default();
- match data_store.get_deposit(key) {
- Option::Some(stored_deposit) => deposit = stored_deposit,
- Option::None => panic(array![DepositError::EMPTY_DEPOSIT, key])
- }
+ let deposit = data_store.get_deposit(key);
assert(ContractAddressZeroable::is_non_zero(deposit.account), DepositError::EMPTY_DEPOSIT);
assert(
@@ -173,21 +171,27 @@ fn cancel_deposit(
if deposit.initial_long_token_amount > 0 {
deposit_vault
.transfer_out(
- deposit.initial_long_token, deposit.account, deposit.initial_long_token_amount
+ deposit_vault.contract_address,
+ deposit.initial_long_token,
+ deposit.account,
+ deposit.initial_long_token_amount
);
}
if deposit.initial_short_token_amount > 0 {
deposit_vault
.transfer_out(
- deposit.initial_short_token, deposit.account, deposit.initial_short_token_amount
+ deposit_vault.contract_address,
+ deposit.initial_short_token,
+ deposit.account,
+ deposit.initial_short_token_amount
);
}
event_emitter.emit_deposit_cancelled(key, reason, reason_bytes.span());
- let event_log_data = EventLogData { cant_be_empty: 0 };
- after_deposit_cancellation(key, deposit, event_log_data, event_emitter);
+ let mut log_data: LogData = Default::default();
+ after_deposit_cancellation(key, deposit, log_data);
gas_utils::pay_execution_fee_deposit(
data_store,
diff --git a/src/deposit/deposit_vault.cairo b/src/deposit/deposit_vault.cairo
index 04fe1508..6d31914e 100644
--- a/src/deposit/deposit_vault.cairo
+++ b/src/deposit/deposit_vault.cairo
@@ -29,7 +29,11 @@ trait IDepositVault {
/// * `receiver` - The address of the receiver.
/// * `amount` - The amount of tokens to transfer.
fn transfer_out(
- ref self: TContractState, token: ContractAddress, receiver: ContractAddress, amount: u128,
+ ref self: TContractState,
+ sender: ContractAddress,
+ token: ContractAddress,
+ receiver: ContractAddress,
+ amount: u256,
);
/// Records a token transfer into the contract.
@@ -37,7 +41,17 @@ trait IDepositVault {
/// * `token` - The token address to transfer.
/// # Returns
/// * The amount of tokens transferred.
- fn record_transfer_in(ref self: TContractState, token: ContractAddress) -> u128;
+ fn record_transfer_in(ref self: TContractState, token: ContractAddress) -> u256;
+
+ /// this can be used to update the tokenBalances in case of token burns
+ /// or similar balance changes
+ /// the prevBalance is not validated to be more than the nextBalance as this
+ /// could allow someone to block this call by transferring into the contract
+ /// # Arguments
+ /// * `token` - The token to record the burn for
+ /// # Return
+ /// The new balance
+ fn sync_token_balance(ref self: TContractState, token: ContractAddress) -> u256;
}
#[starknet::contract]
@@ -50,7 +64,6 @@ mod DepositVault {
use core::zeroable::Zeroable;
use starknet::{get_caller_address, ContractAddress, contract_address_const};
- use debug::PrintTrait;
// Local imports.
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
@@ -80,8 +93,8 @@ mod DepositVault {
#[constructor]
fn constructor(
ref self: ContractState,
- role_store_address: ContractAddress,
data_store_address: ContractAddress,
+ role_store_address: ContractAddress,
) {
self.data_store.write(IDataStoreDispatcher { contract_address: data_store_address });
self.role_store.write(IRoleStoreDispatcher { contract_address: role_store_address });
@@ -91,7 +104,7 @@ mod DepositVault {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl DepositVaultImpl of super::IDepositVault {
fn initialize(
ref self: ContractState,
@@ -105,17 +118,23 @@ mod DepositVault {
fn transfer_out(
ref self: ContractState,
+ sender: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
- amount: u128,
+ amount: u256,
) {
let mut state: StrictBank::ContractState = StrictBank::unsafe_new_contract_state();
- IStrictBank::transfer_out(ref state, token, receiver, amount);
+ IStrictBank::transfer_out(ref state, sender, token, receiver, amount);
}
- fn record_transfer_in(ref self: ContractState, token: ContractAddress) -> u128 {
- // TODO
- 0
+ fn record_transfer_in(ref self: ContractState, token: ContractAddress) -> u256 {
+ let mut state: StrictBank::ContractState = StrictBank::unsafe_new_contract_state();
+ IStrictBank::record_transfer_in(ref state, token)
+ }
+
+ fn sync_token_balance(ref self: ContractState, token: ContractAddress) -> u256 {
+ let mut state: StrictBank::ContractState = StrictBank::unsafe_new_contract_state();
+ IStrictBank::sync_token_balance(ref state, token)
}
}
}
diff --git a/src/deposit/error.cairo b/src/deposit/error.cairo
index 3a936f54..8d4fe9c8 100644
--- a/src/deposit/error.cairo
+++ b/src/deposit/error.cairo
@@ -4,4 +4,19 @@ mod DepositError {
const CANT_BE_ZERO: felt252 = 'deposit account cant be 0';
const EMPTY_DEPOSIT_AMOUNTS: felt252 = 'empty_deposit_amounts';
const EMPTY_DEPOSIT: felt252 = 'empty_deposit';
+ const EMPTY_DEPOSIT_AMOUNTS_AFTER_SWAP: felt252 = 'empty deposit amount after swap';
+
+
+ fn MIN_MARKET_TOKENS(received: u256, expected: u256) {
+ let mut data = array!['invalid swap output token'];
+ data.append(received.try_into().expect('u256 into felt failed'));
+ data.append(expected.try_into().expect('u256 into felt failed'));
+ panic(data)
+ }
+
+ fn INVALID_POOL_VALUE_FOR_DEPOSIT(pool_value: u256) {
+ let mut data = array!['invalid pool value for deposit'];
+ data.append(pool_value.try_into().expect('u256 into felt failed'));
+ panic(data)
+ }
}
diff --git a/src/deposit/execute_deposit_utils.cairo b/src/deposit/execute_deposit_utils.cairo
index 519fb7ef..05f3b80e 100644
--- a/src/deposit/execute_deposit_utils.cairo
+++ b/src/deposit/execute_deposit_utils.cairo
@@ -8,16 +8,38 @@
use starknet::ContractAddress;
use result::ResultTrait;
-use debug::PrintTrait;
// Local imports.
-use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
+use satoru::bank::bank::{IBankDispatcher, IBankDispatcherTrait};
+use satoru::callback::callback_utils::after_deposit_execution;
+use satoru::data::{
+ keys::{deposit_fee_type, ui_deposit_fee_type, max_pnl_factor_for_deposits},
+ data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait}
+};
+use satoru::deposit::{
+ deposit_vault::{IDepositVaultDispatcher, IDepositVaultDispatcherTrait}, error::DepositError
+};
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
-use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait};
-use satoru::deposit::deposit_vault::{IDepositVaultDispatcher, IDepositVaultDispatcherTrait};
+use satoru::event::event_utils::{LogData, LogDataTrait, ContractAddressDictValue, I256252DictValue};
+use satoru::utils::serializable_dict::{SerializableFelt252Dict, SerializableFelt252DictTrait};
+use satoru::fee::fee_utils;
+use satoru::gas::gas_utils::pay_execution_fee_deposit;
+use satoru::market::{
+ market::Market, market_token::{IMarketTokenDispatcher, IMarketTokenDispatcherTrait},
+ market_utils
+};
use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait};
-use satoru::price::price::Price;
-use satoru::market::market::Market;
-use satoru::utils::span32::Span32;
+use satoru::oracle::{oracle::{IOracleDispatcher, IOracleDispatcherTrait}, oracle_utils};
+use satoru::price::price::{Price, PriceTrait};
+use satoru::pricing::swap_pricing_utils::{
+ get_swap_fees, get_price_impact_usd, GetPriceImpactUsdParams
+};
+use satoru::swap::swap_utils;
+use satoru::swap::error::SwapError;
+use satoru::utils::{
+ calc::{to_unsigned, to_signed}, i256::{i256, i256_new, i256_neg}, precision, span32::Span32,
+ starknet_utils::{sn_gasleft, sn_gasprice}
+};
+use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
/// Struct used in executeDeposit to avoid stack too deep errors
#[derive(Drop, Serde)]
@@ -39,7 +61,7 @@ struct ExecuteDepositParams {
/// `keeper` the address of the keeper executing the deposit.
keeper: ContractAddress,
/// `starting_gas` the starting amount of gas.
- starting_gas: u128
+ starting_gas: u256
}
/// Struct used in executeDeposit to avoid stack too deep errors
@@ -62,47 +84,406 @@ struct _ExecuteDepositParams {
/// `token_out_price` Price of token_out.
token_out_price: Price,
/// `amount` Amount of token_in.
- amount: u128,
+ amount: u256,
/// `price_impact_usd` Price impact in USD.
- price_impact_usd: u128
+ price_impact_usd: i256
}
+#[derive(Drop, Default)]
struct ExecuteDepositCache {
- long_token_amount: u128,
- short_token_amount: u128,
- long_token_usd: u128,
- short_token_usd: u128,
- received_market_tokens: u128,
- price_impact_usd: i128
+ long_token_amount: u256,
+ short_token_amount: u256,
+ long_token_usd: u256,
+ short_token_usd: u256,
+ received_market_tokens: u256,
+ price_impact_usd: i256
}
/// Executes a deposit.
/// # Arguments
/// * `params` - ExecuteDepositParams.
-#[inline(always)]
-fn execute_deposit(params: ExecuteDepositParams) { //TODO
+fn execute_deposit(params: ExecuteDepositParams) {
+ // 63/64 gas is forwarded to external calls, reduce the startingGas to account for this
+ let starting_gas = params.starting_gas - sn_gasleft(array![]) / 63;
+
+ let deposit = params.data_store.get_deposit(params.key);
+ params.data_store.remove_deposit(params.key, deposit.account);
+
+ let mut cache: ExecuteDepositCache = Default::default();
+
+ assert(deposit.account.is_non_zero(), DepositError::EMPTY_DEPOSIT);
+
+ oracle_utils::validate_block_number_within_range(
+ params.min_oracle_block_numbers.span(),
+ params.max_oracle_block_numbers.span(),
+ deposit.updated_at_block,
+ );
+
+ let market = market_utils::get_enabled_market(params.data_store, deposit.market);
+ let prices = market_utils::get_market_prices(params.oracle, market);
+
+ // deposits should improve the pool state but it should be checked if
+ // the max pnl factor for deposits is exceeded as this would lead to the
+ // price of the market token decreasing below a target minimum percentage
+ // due to pnl
+ // note that this is just a validation for deposits, there is no actual
+ // minimum price for a market token
+ market_utils::validate_max_pnl(
+ params.data_store,
+ market,
+ prices,
+ max_pnl_factor_for_deposits(),
+ max_pnl_factor_for_deposits(),
+ );
+
+ cache
+ .long_token_amount =
+ swap(
+ @params,
+ deposit.long_token_swap_path,
+ deposit.initial_long_token,
+ deposit.initial_long_token_amount,
+ market.market_token,
+ market.long_token,
+ deposit.ui_fee_receiver,
+ );
+
+ cache
+ .short_token_amount =
+ swap(
+ @params,
+ deposit.short_token_swap_path,
+ deposit.initial_short_token,
+ deposit.initial_short_token_amount,
+ market.market_token,
+ market.short_token,
+ deposit.ui_fee_receiver,
+ );
+
+ if cache.long_token_amount == 0 && cache.short_token_amount == 0 {
+ panic_with_felt252(DepositError::EMPTY_DEPOSIT_AMOUNTS_AFTER_SWAP)
+ }
+
+ cache.long_token_usd = cache.long_token_amount * prices.long_token_price.mid_price();
+ cache.short_token_usd = cache.short_token_amount * prices.short_token_price.mid_price();
+
+ cache
+ .price_impact_usd =
+ get_price_impact_usd(
+ GetPriceImpactUsdParams {
+ data_store: params.data_store,
+ market: market,
+ token_a: market.long_token,
+ token_b: market.short_token,
+ price_for_token_a: prices.long_token_price.mid_price(),
+ price_for_token_b: prices.short_token_price.mid_price(),
+ usd_delta_for_token_a: to_signed(cache.long_token_usd, true),
+ usd_delta_for_token_b: to_signed(cache.short_token_usd, true),
+ }
+ );
+
+ if cache.long_token_amount > 0 {
+ let mut _params = _ExecuteDepositParams {
+ market: market,
+ account: deposit.account,
+ receiver: deposit.receiver,
+ ui_fee_receiver: deposit.ui_fee_receiver,
+ token_in: market.long_token,
+ token_out: market.short_token,
+ token_in_price: prices.long_token_price,
+ token_out_price: prices.short_token_price,
+ amount: cache.long_token_amount,
+ price_impact_usd: precision::mul_div_ival(
+ cache.price_impact_usd,
+ cache.long_token_usd,
+ cache.long_token_usd + cache.short_token_usd
+ )
+ };
+
+ cache.received_market_tokens += execute_deposit_helper(@params, ref _params);
+ }
+
+ if cache.short_token_amount > 0 {
+ let mut _params = _ExecuteDepositParams {
+ market: market,
+ account: deposit.account,
+ receiver: deposit.receiver,
+ ui_fee_receiver: deposit.ui_fee_receiver,
+ token_in: market.short_token,
+ token_out: market.long_token,
+ token_in_price: prices.short_token_price,
+ token_out_price: prices.long_token_price,
+ amount: cache.short_token_amount,
+ price_impact_usd: precision::mul_div_ival(
+ cache.price_impact_usd,
+ cache.short_token_usd,
+ cache.long_token_usd + cache.short_token_usd
+ )
+ };
+
+ cache.received_market_tokens += execute_deposit_helper(@params, ref _params);
+ }
+
+ if cache.received_market_tokens < deposit.min_market_tokens {
+ DepositError::MIN_MARKET_TOKENS(cache.received_market_tokens, deposit.min_market_tokens);
+ }
+
+ market_utils::validate_market_token_balance_check(params.data_store, market);
+
+ (params.event_emitter)
+ .emit_deposit_executed(
+ params.key,
+ cache.long_token_amount,
+ cache.short_token_amount,
+ cache.received_market_tokens,
+ );
+ // let mut event_data: LogData = Default::default();
+ // event_data.uint_dict.insert_single('received_market_tokens', cache.received_market_tokens);
+ // after_deposit_execution(params.key, deposit, event_data);
+
+ pay_execution_fee_deposit(
+ params.data_store,
+ params.event_emitter,
+ params.deposit_vault,
+ deposit.execution_fee,
+ params.starting_gas,
+ params.keeper,
+ deposit.account,
+ );
}
/// Executes a deposit.
/// # Arguments
-/// * `params` - ExecuteDepositParams.
-/// * `_params` - _ExecuteDepositParams.
-#[inline(always)]
-fn _execute_deposit(params: ExecuteDepositParams, _params: _ExecuteDepositParams) -> u128 {
- //TODO
- 0
+/// * `params` - @ExecuteDepositParams.
+/// * `_params` - @_ExecuteDepositParams.
+fn execute_deposit_helper(
+ params: @ExecuteDepositParams, ref _params: _ExecuteDepositParams
+) -> u256 {
+ // for markets where longToken == shortToken, the price impact factor should be set to zero
+ // in which case, the priceImpactUsd would always equal zero
+ let mut fees = get_swap_fees(
+ *params.data_store,
+ _params.market.market_token,
+ _params.amount,
+ _params.price_impact_usd > Zeroable::zero(),
+ _params.ui_fee_receiver,
+ );
+
+ fee_utils::increment_claimable_fee_amount(
+ *params.data_store,
+ *params.event_emitter,
+ _params.market.market_token,
+ _params.token_in,
+ fees.fee_receiver_amount,
+ deposit_fee_type(),
+ );
+
+ fee_utils::increment_claimable_ui_fee_amount(
+ *params.data_store,
+ *params.event_emitter,
+ _params.ui_fee_receiver,
+ _params.market.market_token,
+ _params.token_in,
+ fees.ui_fee_amount,
+ ui_deposit_fee_type(),
+ );
+
+ (*params.event_emitter)
+ .emit_swap_fees_collected(
+ _params.market.market_token,
+ _params.token_in,
+ _params.token_in_price.min,
+ 'deposit',
+ fees.clone(),
+ );
+
+ let pool_value_info = market_utils::get_pool_value_info(
+ *params.data_store,
+ _params.market,
+ (*params.oracle).get_primary_price(_params.market.index_token),
+ if _params.token_in == _params.market.long_token {
+ _params.token_in_price
+ } else {
+ _params.token_out_price
+ },
+ if _params.token_in == _params.market.short_token {
+ _params.token_in_price
+ } else {
+ _params.token_out_price
+ },
+ max_pnl_factor_for_deposits(),
+ true,
+ );
+
+ if pool_value_info.pool_value < Zeroable::zero() {
+ DepositError::INVALID_POOL_VALUE_FOR_DEPOSIT(pool_value_info.pool_value.mag);
+ }
+
+ let mut mint_amount = 0;
+ let pool_value = to_unsigned(pool_value_info.pool_value);
+ let market_tokens_supply = market_utils::get_market_token_supply(
+ IMarketTokenDispatcher { contract_address: _params.market.market_token }
+ );
+
+ if pool_value == Zeroable::zero() && market_tokens_supply > 0 {
+ DepositError::INVALID_POOL_VALUE_FOR_DEPOSIT(pool_value_info.pool_value.mag);
+ }
+
+ (*params.event_emitter)
+ .emit_market_pool_value_info(
+ _params.market.market_token, pool_value_info, market_tokens_supply,
+ );
+
+ // the pool_value and market_tokens_supply is cached for the mint_amount calculation below
+ // so the effect of any positive price impact on the pool_value and market_tokens_supply
+ // would not be accounted for
+ //
+ // for most cases, this should not be an issue, since the pool_value and market_tokens_supply
+ // should have been proportionately increased
+ //
+ // e.g. if the pool_value is $100 and market_tokens_supply is 100, and there is a positive price impact
+ // of $10, the pool_value should have increased by $10 and the market_tokens_supply should have been increased by 10
+ //
+ // there is a case where this may be an issue which is when all tokens are withdrawn from an existing market
+ // and the market_tokens_supply is reset to zero, but the pool_value is not entirely zero
+ // the case where this happens should be very rare and during withdrawal the pool_value should be close to zero
+ //
+ // however, in case this occurs, the usdToMarketTokenAmount will mint an additional number of market tokens
+ // proportional to the existing pool_value
+ //
+ // since the pool_value and market_tokens_supply is cached, this could occur once during positive price impact
+ // and again when calculating the mint_amount
+ //
+ // to avoid this, set the price_impact_usd to be zero for this case
+
+ if _params.price_impact_usd > Zeroable::zero() && market_tokens_supply == Zeroable::zero() {
+ _params.price_impact_usd = i256_new(0, false);
+ }
+
+ if _params.price_impact_usd > Zeroable::zero() {
+ // when there is a positive price impact factor,
+ // tokens from the swap impact pool are used to mint additional market tokens for the user
+ // for example, if 50,000 USDC is deposited and there is a positive price impact
+ // an additional 0.005 ETH may be used to mint market tokens
+ // the swap impact pool is decreased by the used amount
+ //
+ // price_impact_usd is calculated based on pricing assuming only depositAmount of tokenIn
+ // was added to the pool
+ // since impactAmount of tokenOut is added to the pool here, the calculation of
+ // the price impact would not be entirely accurate
+ //
+ // it is possible that the addition of the positive impact amount of tokens into the pool
+ // could increase the imbalance of the pool, for most cases this should not be a significant
+ // change compared to the improvement of balance from the actual deposit
+
+ let positive_impact_amount = market_utils::apply_swap_impact_with_cap(
+ *params.data_store,
+ *params.event_emitter,
+ _params.market.market_token,
+ _params.token_out,
+ _params.token_out_price,
+ _params.price_impact_usd,
+ );
+
+ // calculate the usd amount using positiveImpactAmount since it may
+ // be capped by the max available amount in the impact pool
+ // use tokenOutPrice.max to get the USD value since the positiveImpactAmount
+ // was calculated using a USD value divided by tokenOutPrice.max
+ //
+ // for the initial deposit, the pool value and token supply would be zero
+ // so the market token price is treated as 1 USD
+ //
+ // it is possible for the pool value to be more than zero and the token supply
+ // to be zero, in that case, the market token price is also treated as 1 USD
+ mint_amount +=
+ market_utils::usd_to_market_token_amount(
+ to_unsigned(positive_impact_amount) * _params.token_out_price.max,
+ pool_value,
+ market_tokens_supply,
+ );
+
+ market_utils::apply_delta_to_pool_amount(
+ *params.data_store,
+ *params.event_emitter,
+ _params.market,
+ _params.token_out,
+ positive_impact_amount
+ );
+
+ market_utils::validate_pool_amount(params.data_store, @_params.market, _params.token_out);
+ }
+
+ if (_params.price_impact_usd < Zeroable::zero()) {
+ // when there is a negative price impact factor,
+ // less of the deposit amount is used to mint market tokens
+ // for example, if 10 ETH is deposited and there is a negative price impact
+ // only 9.995 ETH may be used to mint market tokens
+ // the remaining 0.005 ETH will be stored in the swap impact pool
+ let negative_impact_amount = market_utils::apply_swap_impact_with_cap(
+ *params.data_store,
+ *params.event_emitter,
+ _params.market.market_token,
+ _params.token_in,
+ _params.token_in_price,
+ _params.price_impact_usd,
+ );
+
+ fees.amount_after_fees -= to_unsigned(i256_neg(negative_impact_amount));
+ }
+
+ mint_amount +=
+ market_utils::usd_to_market_token_amount(
+ fees.amount_after_fees * _params.token_in_price.min, pool_value, market_tokens_supply,
+ );
+
+ market_utils::apply_delta_to_pool_amount(
+ *params.data_store,
+ *params.event_emitter,
+ _params.market,
+ _params.token_in,
+ to_signed(fees.amount_after_fees + fees.fee_amount_for_pool, true),
+ );
+
+ market_utils::validate_pool_amount(params.data_store, @_params.market, _params.token_in);
+
+ IMarketTokenDispatcher { contract_address: _params.market.market_token }
+ .mint(_params.receiver, mint_amount);
+
+ mint_amount
}
-#[inline(always)]
fn swap(
- params: ExecuteDepositParams,
+ params: @ExecuteDepositParams,
swap_path: Span32,
initial_token: ContractAddress,
- intput_amount: u128,
+ input_amount: u256,
market: ContractAddress,
expected_output_token: ContractAddress,
ui_fee_receiver: ContractAddress
-) -> u128 {
- //TODO
- 0
+) -> u256 {
+ let swap_path_markets = market_utils::get_swap_path_markets(*params.data_store, swap_path);
+
+ let (output_token, output_amount) = swap_utils::swap(
+ @swap_utils::SwapParams {
+ data_store: *params.data_store,
+ event_emitter: *params.event_emitter,
+ oracle: *params.oracle,
+ bank: IBankDispatcher { contract_address: market },
+ key: *params.key,
+ token_in: initial_token,
+ amount_in: input_amount,
+ swap_path_markets: swap_path_markets.span(),
+ min_output_amount: 0,
+ receiver: market,
+ ui_fee_receiver: ui_fee_receiver,
+ }
+ );
+
+ if output_token != expected_output_token {
+ SwapError::INVALID_SWAP_OUTPUT_TOKEN(output_token, expected_output_token)
+ }
+
+ market_utils::validate_market_token_balance_array(*params.data_store, swap_path_markets);
+
+ output_amount
}
diff --git a/src/event/event_emitter.cairo b/src/event/event_emitter.cairo
old mode 100644
new mode 100755
index fbfe2281..1dd825f0
--- a/src/event/event_emitter.cairo
+++ b/src/event/event_emitter.cairo
@@ -9,23 +9,16 @@ use starknet::{ContractAddress, ClassHash};
// Local imports.
use satoru::deposit::deposit::Deposit;
use satoru::withdrawal::withdrawal::Withdrawal;
-use satoru::position::position::Position;
use satoru::market::market_pool_value_info::MarketPoolValueInfo;
use satoru::pricing::swap_pricing_utils::SwapFees;
-use satoru::position::position_event_utils::PositionIncreaseParams;
-use satoru::position::position_utils::DecreasePositionCollateralValues;
-use satoru::order::order::OrderType;
+use satoru::position::{
+ position::Position, position_event_utils::PositionIncreaseParams,
+ position_utils::DecreasePositionCollateralValues
+};
use satoru::price::price::Price;
use satoru::pricing::position_pricing_utils::PositionFees;
-use satoru::order::order::{Order, SecondaryOrderType};
-use satoru::utils::span32::{Span32, DefaultSpan32};
-use satoru::utils::i128::{I128Div, I128Mul, I128Serde};
-
-
-//TODO: OrderCollatDeltaAmountAutoUpdtd must be renamed back to OrderCollateralDeltaAmountAutoUpdated when string will be allowed as event argument
-//TODO: AfterWithdrawalCancelError must be renamed back to AfterWithdrawalCancellationError when string will be allowed as event argument
-//TODO: CumulativeBorrowingFactorUpdatd must be renamed back to CumulativeBorrowingFactorUpdated when string will be allowed as event argument
-//TODO: ClaimableFundingPerSizeUpdatd must be renamed back to ClaimableFundingAmountPerSizeUpdated when string will be allowed as event argument
+use satoru::order::order::{Order, SecondaryOrderType, OrderType};
+use satoru::utils::{i256::i256, span32::{Span32, DefaultSpan32}};
// *************************************************************************
// Interface of the `EventEmitter` contract.
@@ -38,10 +31,10 @@ trait IEventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- time_key: u128,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ time_key: u256,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
);
/// Emits the `ClaimableFundingUpdated` event.
@@ -50,14 +43,14 @@ trait IEventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
);
/// Emits the `PositionImpactPoolAmountUpdated` event.
fn emit_position_impact_pool_amount_updated(
- ref self: TContractState, market: ContractAddress, delta: u128, next_value: u128,
+ ref self: TContractState, market: ContractAddress, delta: i256, next_value: u256,
);
/// Emits the `SwapImpactPoolAmountUpdated` event.
@@ -65,8 +58,8 @@ trait IEventEmitter {
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: i256,
+ next_value: u256,
);
/// Emits the `MarketCreated` event.
@@ -93,8 +86,8 @@ trait IEventEmitter {
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: u256,
+ next_value: u256,
fee_type: felt252
);
@@ -104,9 +97,9 @@ trait IEventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
fee_type: felt252
);
@@ -115,7 +108,7 @@ trait IEventEmitter {
ref self: TContractState,
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128
+ fee_amount: u256
);
/// Emits the `UiFeesClaimed` event.
@@ -124,21 +117,20 @@ trait IEventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128,
- next_pool_value: u128
+ fee_amount: u256,
+ next_pool_value: u256
);
/// Emits the `DepositCreated` event.
- #[inline(always)]
fn emit_deposit_created(ref self: TContractState, key: felt252, deposit: Deposit);
/// Emits the `DepositExecuted` event.
fn emit_deposit_executed(
ref self: TContractState,
key: felt252,
- long_token_amount: u128,
- short_token_amount: u128,
- received_market_tokens: u128,
+ long_token_amount: u256,
+ short_token_amount: u256,
+ received_market_tokens: u256,
);
/// Emits the `DepositCancelled` event.
@@ -147,7 +139,6 @@ trait IEventEmitter {
);
/// Emits the `WithdrawalCreated` event.
- #[inline(always)]
fn emit_withdrawal_created(ref self: TContractState, key: felt252, withdrawal: Withdrawal);
/// Emits the `WithdrawalExecuted` event.
@@ -159,18 +150,16 @@ trait IEventEmitter {
);
/// Emits the `PositionIncrease` event.
- #[inline(always)]
fn emit_position_increase(ref self: TContractState, params: PositionIncreaseParams);
/// Emits the `PositionDecrease` event.
- #[inline(always)]
fn emit_position_decrease(
ref self: TContractState,
order_key: felt252,
position_key: felt252,
position: Position,
- size_delta_usd: u128,
- collateral_delta_amount: u128,
+ size_delta_usd: u256,
+ collateral_delta_amount: u256,
order_type: OrderType,
values: DecreasePositionCollateralValues,
index_token_price: Price,
@@ -181,9 +170,9 @@ trait IEventEmitter {
fn emit_insolvent_close_info(
ref self: TContractState,
order_key: felt252,
- position_collateral_amount: u128,
- base_pnl_usd: u128,
- remaining_cost_usd: u128
+ position_collateral_amount: u256,
+ base_pnl_usd: i256,
+ remaining_cost_usd: u256
);
/// Emits the `InsufficientFundingFeePayment` event.
@@ -191,39 +180,36 @@ trait IEventEmitter {
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
- expected_amount: u128,
- amount_paid_in_collateral_token: u128,
- amount_paid_in_secondary_output_token: u128
+ expected_amount: u256,
+ amount_paid_in_collateral_token: u256,
+ amount_paid_in_secondary_output_token: u256
);
/// Emits the `PositionFeesCollected` event.
- #[inline(always)]
fn emit_position_fees_collected(
ref self: TContractState,
order_key: felt252,
position_key: felt252,
market: ContractAddress,
collateral_token: ContractAddress,
- trade_size_usd: u128,
+ trade_size_usd: u256,
is_increase: bool,
fees: PositionFees
);
/// Emits the `PositionFeesInfo` event.
- #[inline(always)]
fn emit_position_fees_info(
ref self: TContractState,
order_key: felt252,
position_key: felt252,
market: ContractAddress,
collateral_token: ContractAddress,
- trade_size_usd: u128,
+ trade_size_usd: u256,
is_increase: bool,
fees: PositionFees
);
/// Emits the `OrderCreated` event.
- #[inline(always)]
fn emit_order_created(ref self: TContractState, key: felt252, order: Order);
/// Emits the `OrderExecuted` event.
@@ -235,23 +221,23 @@ trait IEventEmitter {
fn emit_order_updated(
ref self: TContractState,
key: felt252,
- size_delta_usd: u128,
- acceptable_price: u128,
- trigger_price: u128,
- min_output_amount: u128
+ size_delta_usd: u256,
+ acceptable_price: u256,
+ trigger_price: u256,
+ min_output_amount: u256
);
/// Emits the `OrderSizeDeltaAutoUpdated` event.
fn emit_order_size_delta_auto_updated(
- ref self: TContractState, key: felt252, size_delta_usd: u128, next_size_delta_usd: u128
+ ref self: TContractState, key: felt252, size_delta_usd: u256, next_size_delta_usd: u256
);
- /// Emits the `OrderCollatDeltaAmountAutoUpdtd` event.
+ /// Emits the `OrderCollateralDeltaAmountAutoUpdated` event.
fn emit_order_collateral_delta_amount_auto_updated(
ref self: TContractState,
key: felt252,
- collateral_delta_amount: u128,
- next_collateral_delta_amount: u128
+ collateral_delta_amount: u256,
+ next_collateral_delta_amount: u256
);
/// Emits the `OrderCancelled` event.
@@ -270,9 +256,9 @@ trait IEventEmitter {
market: ContractAddress,
token: ContractAddress,
affiliate: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256
);
/// Emits the `AffiliateRewardClaimed` event.
@@ -282,8 +268,8 @@ trait IEventEmitter {
token: ContractAddress,
affiliate: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
);
/// Emits the `AfterDepositExecutionError` event.
@@ -299,7 +285,7 @@ trait IEventEmitter {
ref self: TContractState, key: felt252, withdrawal: Withdrawal
);
- /// Emits the `AfterWithdrawalCancelError` event.
+ /// Emits the `AfterWithdrawalCancellationError` event.
fn emit_after_withdrawal_cancellation_error(
ref self: TContractState, key: felt252, withdrawal: Withdrawal
);
@@ -319,7 +305,7 @@ trait IEventEmitter {
market: ContractAddress,
is_long: bool,
pnl_to_pool_factor: felt252,
- max_pnl_factor: u128,
+ max_pnl_factor: u256,
should_enable_adl: bool,
);
@@ -340,7 +326,7 @@ trait IEventEmitter {
/// Emits the `SetUint` event.
fn emit_set_uint(
- ref self: TContractState, key: felt252, data_bytes: Span, value: u128
+ ref self: TContractState, key: felt252, data_bytes: Span, value: u256
);
/// Emits the `SetInt` event.
@@ -404,9 +390,9 @@ trait IEventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
);
/// Emits the `SetPriceFeed` event.
@@ -415,9 +401,9 @@ trait IEventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
);
/// Emits the `SignalPendingAction` event.
@@ -432,21 +418,20 @@ trait IEventEmitter {
/// Emits the `KeeperExecutionFee` event.
fn emit_keeper_execution_fee(
- ref self: TContractState, keeper: ContractAddress, execution_fee_amount: u128
+ ref self: TContractState, keeper: ContractAddress, execution_fee_amount: u256
);
/// Emits the `ExecutionFeeRefund` event.
fn emit_execution_fee_refund(
- ref self: TContractState, receiver: ContractAddress, refund_fee_amount: u128
+ ref self: TContractState, receiver: ContractAddress, refund_fee_amount: u256
);
/// Emits the `MarketPoolValueInfo` event.
- #[inline(always)]
fn emit_market_pool_value_info(
ref self: TContractState,
market: ContractAddress,
market_pool_value_info: MarketPoolValueInfo,
- market_tokens_supply: u128
+ market_tokens_supply: u256
);
/// Emits the `PoolAmountUpdated` event.
@@ -454,8 +439,8 @@ trait IEventEmitter {
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
);
/// Emits the `OpenInterestInTokensUpdated` event.
@@ -464,8 +449,8 @@ trait IEventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
);
/// Emits the `OpenInterestUpdated` event.
@@ -474,8 +459,8 @@ trait IEventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
);
/// Emits the `VirtualSwapInventoryUpdated` event.
@@ -484,8 +469,8 @@ trait IEventEmitter {
market: ContractAddress,
is_long_token: bool,
virtual_market_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
);
/// Emits the `VirtualPositionInventoryUpdated` event.
@@ -493,8 +478,8 @@ trait IEventEmitter {
ref self: TContractState,
token: ContractAddress,
virtual_token_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: i256
);
/// Emits the `CollateralSumUpdated` event.
@@ -503,17 +488,17 @@ trait IEventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
);
- /// Emits the `CumulativeBorrowingFactorUpdatd` event.
+ /// Emits the `CumulativeBorrowingFactorUpdated` event.
fn emit_cumulative_borrowing_factor_updated(
ref self: TContractState,
market: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
);
/// Emits the `FundingFeeAmountPerSizeUpdated` event.
@@ -522,29 +507,29 @@ trait IEventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
);
- /// Emits the `ClaimableFundingPerSizeUpdatd` event.
+ /// Emits the `ClaimableFundingAmountPerSizeUpdated` event.
fn emit_claimable_funding_amount_per_size_updated(
ref self: TContractState,
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
);
/// Emits the `FundingFeesClaimed` event.
- fn emit_founding_fees_claimed(
+ fn emit_funding_fees_claimed(
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
);
/// Emits the `CollateralClaimed` event.
@@ -554,22 +539,21 @@ trait IEventEmitter {
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- time_key: u128,
- amount: u128,
- next_pool_value: u128
+ time_key: u256,
+ amount: u256,
+ next_pool_value: u256
);
- /// Emits the `UiFeeFactorUpdated` event.
fn emit_ui_fee_factor_updated(
- ref self: TContractState, account: ContractAddress, ui_fee_factor: u128
+ ref self: TContractState, account: ContractAddress, ui_fee_factor: u256
);
/// Emits the `OraclePriceUpdate` event.
fn emit_oracle_price_update(
ref self: TContractState,
token: ContractAddress,
- min_price: u128,
- max_price: u128,
+ min_price: u256,
+ max_price: u256,
is_price_feed: bool
);
@@ -590,22 +574,21 @@ trait IEventEmitter {
receiver: ContractAddress,
token_in: ContractAddress,
token_out: ContractAddress,
- token_in_price: u128,
- token_out_price: u128,
- amount_in: u128,
- amount_in_after_fees: u128,
- amount_out: u128,
- price_impact_usd: i128,
- price_impact_amount: i128
+ token_in_price: u256,
+ token_out_price: u256,
+ amount_in: u256,
+ amount_in_after_fees: u256,
+ amount_out: u256,
+ price_impact_usd: i256,
+ price_impact_amount: i256
);
/// Emits the `SwapFeesCollected` event.
- #[inline(always)]
fn emit_swap_fees_collected(
ref self: TContractState,
market: ContractAddress,
token: ContractAddress,
- token_price: u128,
+ token_price: u256,
action: felt252,
fees: SwapFees
);
@@ -613,8 +596,8 @@ trait IEventEmitter {
fn emit_oracle_price_updated(
ref self: TContractState,
token: ContractAddress,
- min_price: u128,
- max_price: u128,
+ min_price: u256,
+ max_price: u256,
is_price_feed: bool
);
@@ -625,13 +608,13 @@ trait IEventEmitter {
);
fn emit_set_tier(
- ref self: TContractState, tier_id: u128, total_rebate: u128, discount_share: u128
+ ref self: TContractState, tier_id: u256, total_rebate: u256, discount_share: u256
);
- fn emit_set_referrer_tier(ref self: TContractState, referrer: ContractAddress, tier_id: u128);
+ fn emit_set_referrer_tier(ref self: TContractState, referrer: ContractAddress, tier_id: u256);
fn emit_set_referrer_discount_share(
- ref self: TContractState, referrer: ContractAddress, discount_share: u128
+ ref self: TContractState, referrer: ContractAddress, discount_share: u256
);
fn emit_register_code(ref self: TContractState, account: ContractAddress, code: felt252);
@@ -672,7 +655,7 @@ mod EventEmitter {
use satoru::pricing::position_pricing_utils::PositionFees;
use satoru::order::order::{Order, SecondaryOrderType};
use satoru::utils::span32::{Span32, DefaultSpan32};
- use satoru::utils::i128::{I128Div, I128Mul, I128Serde};
+ use satoru::utils::i256::i256;
// *************************************************************************
// STORAGE
@@ -706,7 +689,7 @@ mod EventEmitter {
OrderExecuted: OrderExecuted,
OrderUpdated: OrderUpdated,
OrderSizeDeltaAutoUpdated: OrderSizeDeltaAutoUpdated,
- OrderCollatDeltaAmountAutoUpdtd: OrderCollatDeltaAmountAutoUpdtd,
+ OrderCollateralDeltaAmountAutoUpdated: OrderCollateralDeltaAmountAutoUpdated,
OrderCancelled: OrderCancelled,
OrderFrozen: OrderFrozen,
PositionIncrease: PositionIncrease,
@@ -720,7 +703,7 @@ mod EventEmitter {
AfterDepositExecutionError: AfterDepositExecutionError,
AfterDepositCancellationError: AfterDepositCancellationError,
AfterWithdrawalExecutionError: AfterWithdrawalExecutionError,
- AfterWithdrawalCancelError: AfterWithdrawalCancelError,
+ AfterWithdrawalCancellationError: AfterWithdrawalCancellationError,
AfterOrderExecutionError: AfterOrderExecutionError,
AfterOrderCancellationError: AfterOrderCancellationError,
AfterOrderFrozenError: AfterOrderFrozenError,
@@ -753,9 +736,9 @@ mod EventEmitter {
VirtualSwapInventoryUpdated: VirtualSwapInventoryUpdated,
VirtualPositionInventoryUpdated: VirtualPositionInventoryUpdated,
CollateralSumUpdated: CollateralSumUpdated,
- CumulativeBorrowingFactorUpdatd: CumulativeBorrowingFactorUpdatd,
+ CumulativeBorrowingFactorUpdated: CumulativeBorrowingFactorUpdated,
FundingFeeAmountPerSizeUpdated: FundingFeeAmountPerSizeUpdated,
- ClaimableFundingPerSizeUpdatd: ClaimableFundingPerSizeUpdatd,
+ ClaimableFundingAmountPerSizeUpdated: ClaimableFundingAmountPerSizeUpdated,
FundingFeesClaimed: FundingFeesClaimed,
CollateralClaimed: CollateralClaimed,
UiFeeFactorUpdated: UiFeeFactorUpdated,
@@ -781,10 +764,10 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- time_key: u128,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ time_key: u256,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
}
#[derive(Drop, starknet::Event)]
@@ -792,24 +775,24 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
}
#[derive(Drop, starknet::Event)]
struct PositionImpactPoolAmountUpdated {
market: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: i256,
+ next_value: u256,
}
#[derive(Drop, starknet::Event)]
struct SwapImpactPoolAmountUpdated {
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: i256,
+ next_value: u256,
}
#[derive(Drop, starknet::Event)]
@@ -833,8 +816,8 @@ mod EventEmitter {
struct ClaimableFeeAmountUpdated {
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: u256,
+ next_value: u256,
fee_type: felt252,
}
@@ -843,9 +826,9 @@ mod EventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
fee_type: felt252,
}
@@ -853,7 +836,7 @@ mod EventEmitter {
struct FeesClaimed {
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128,
+ fee_amount: u256,
}
#[derive(Drop, starknet::Event)]
@@ -861,8 +844,8 @@ mod EventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128,
- next_pool_value: u128,
+ fee_amount: u256,
+ next_pool_value: u256,
}
#[derive(Drop, starknet::Event)]
@@ -876,20 +859,20 @@ mod EventEmitter {
initial_short_token: ContractAddress,
long_token_swap_path: Span32,
short_token_swap_path: Span32,
- initial_long_token_amount: u128,
- initial_short_token_amount: u128,
- min_market_tokens: u128,
+ initial_long_token_amount: u256,
+ initial_short_token_amount: u256,
+ min_market_tokens: u256,
updated_at_block: u64,
- execution_fee: u128,
- callback_gas_limit: u128,
+ execution_fee: u256,
+ callback_gas_limit: u256,
}
#[derive(Drop, starknet::Event)]
struct DepositExecuted {
key: felt252,
- long_token_amount: u128,
- short_token_amount: u128,
- received_market_tokens: u128,
+ long_token_amount: u256,
+ short_token_amount: u256,
+ received_market_tokens: u256,
}
#[derive(Drop, starknet::Event)]
@@ -906,12 +889,14 @@ mod EventEmitter {
receiver: ContractAddress,
callback_contract: ContractAddress,
market: ContractAddress,
- market_token_amount: u128,
- min_long_token_amount: u128,
- min_short_token_amount: u128,
+ long_token_swap_path: Span32,
+ short_token_swap_path: Span32,
+ market_token_amount: u256,
+ min_long_token_amount: u256,
+ min_short_token_amount: u256,
updated_at_block: u64,
- execution_fee: u128,
- callback_gas_limit: u128,
+ execution_fee: u256,
+ callback_gas_limit: u256,
}
#[derive(Drop, starknet::Event)]
@@ -931,24 +916,24 @@ mod EventEmitter {
account: ContractAddress,
market: ContractAddress,
collateral_token: ContractAddress,
- size_in_usd: u128,
- size_in_tokens: u128,
- collateral_amount: u128,
- borrowing_factor: u128,
- funding_fee_amount_per_pize: u128,
- long_token_claimable_funding_amount_per_size: u128,
- short_token_claimable_funding_amount_per_size: u128,
- execution_price: u128,
- index_token_price_max: u128,
- index_token_price_min: u128,
- collateral_token_price_max: u128,
- collateral_token_price_min: u128,
- size_delta_usd: u128,
- size_delta_in_tokens: u128,
+ size_in_usd: u256,
+ size_in_tokens: u256,
+ collateral_amount: u256,
+ borrowing_factor: u256,
+ funding_fee_amount_per_size: u256,
+ long_token_claimable_funding_amount_per_size: u256,
+ short_token_claimable_funding_amount_per_size: u256,
+ execution_price: u256,
+ index_token_price_max: u256,
+ index_token_price_min: u256,
+ collateral_token_price_max: u256,
+ collateral_token_price_min: u256,
+ size_delta_usd: u256,
+ size_delta_in_tokens: u256,
order_type: OrderType,
- collateral_delta_amount: u128,
- price_impact_usd: u128,
- price_impact_amount: u128,
+ collateral_delta_amount: i256,
+ price_impact_usd: i256,
+ price_impact_amount: i256,
is_long: bool,
order_key: felt252,
position_key: felt252
@@ -959,26 +944,26 @@ mod EventEmitter {
account: ContractAddress,
market: ContractAddress,
collateral_token: ContractAddress,
- size_in_usd: u128,
- size_in_tokens: u128,
- collateral_amount: u128,
- borrowing_factor: u128,
- funding_fee_amount_per_pize: u128,
- long_token_claimable_funding_amount_per_size: u128,
- short_token_claimable_funding_amount_per_size: u128,
- execution_price: u128,
- index_token_price_max: u128,
- index_token_price_min: u128,
- collateral_token_price_max: u128,
- collateral_token_price_min: u128,
- size_delta_usd: u128,
- size_delta_in_tokens: u128,
- collateral_delta_amount: u128,
- price_impact_diff_usd: u128,
+ size_in_usd: u256,
+ size_in_tokens: u256,
+ collateral_amount: u256,
+ borrowing_factor: u256,
+ funding_fee_amount_per_size: u256,
+ long_token_claimable_funding_amount_per_size: u256,
+ short_token_claimable_funding_amount_per_size: u256,
+ execution_price: u256,
+ index_token_price_max: u256,
+ index_token_price_min: u256,
+ collateral_token_price_max: u256,
+ collateral_token_price_min: u256,
+ size_delta_usd: u256,
+ size_delta_in_tokens: u256,
+ collateral_delta_amount: u256,
+ price_impact_diff_usd: u256,
order_type: OrderType,
- price_impact_usd: i128,
- base_pnl_usd: i128,
- uncapped_base_pnl_usd: i128,
+ price_impact_usd: i256,
+ base_pnl_usd: i256,
+ uncapped_base_pnl_usd: i256,
is_long: bool,
order_key: felt252,
position_key: felt252
@@ -987,18 +972,18 @@ mod EventEmitter {
#[derive(Drop, starknet::Event)]
struct InsolventClose {
order_key: felt252,
- position_collateral_amount: u128,
- base_pnl_usd: u128,
- remaining_cost_usd: u128
+ position_collateral_amount: u256,
+ base_pnl_usd: i256,
+ remaining_cost_usd: u256
}
#[derive(Drop, starknet::Event)]
struct InsufficientFundingFeePayment {
market: ContractAddress,
token: ContractAddress,
- expected_amount: u128,
- amount_paid_in_collateral_token: u128,
- amount_paid_in_secondary_output_token: u128
+ expected_amount: u256,
+ amount_paid_in_collateral_token: u256,
+ amount_paid_in_secondary_output_token: u256
}
#[derive(Drop, starknet::Event)]
@@ -1011,34 +996,34 @@ mod EventEmitter {
affiliate: ContractAddress,
trader: ContractAddress,
ui_fee_receiver: ContractAddress,
- collateral_token_price_min: u128,
- collateral_token_price_max: u128,
- trade_size_usd: u128,
- total_rebate_factor: u128,
- trader_discount_factor: u128,
- total_rebate_amount: u128,
- trader_discount_amount: u128,
- affiliate_reward_amount: u128,
- funding_fee_amount: u128,
- claimable_long_token_amount: u128,
- claimable_short_token_amount: u128,
- latest_funding_fee_amount_per_size: u128,
- latest_long_token_claimable_funding_amount_per_size: u128,
- latest_short_token_claimable_funding_amount_per_size: u128,
- borrowing_fee_usd: u128,
- borrowing_fee_amount: u128,
- borrowing_fee_receiver_factor: u128,
- borrowing_fee_amount_for_fee_receiver: u128,
- position_fee_factor: u128,
- protocol_fee_amount: u128,
- position_fee_receiver_factor: u128,
- fee_receiver_amount: u128,
- fee_amount_for_pool: u128,
- position_fee_amount_for_pool: u128,
- position_fee_amount: u128,
- total_cost_amount: u128,
- ui_fee_receiver_factor: u128,
- ui_fee_amount: u128,
+ collateral_token_price_min: u256,
+ collateral_token_price_max: u256,
+ trade_size_usd: u256,
+ total_rebate_factor: u256,
+ trader_discount_factor: u256,
+ total_rebate_amount: u256,
+ trader_discount_amount: u256,
+ affiliate_reward_amount: u256,
+ funding_fee_amount: u256,
+ claimable_long_token_amount: u256,
+ claimable_short_token_amount: u256,
+ latest_funding_fee_amount_per_size: u256,
+ latest_long_token_claimable_funding_amount_per_size: u256,
+ latest_short_token_claimable_funding_amount_per_size: u256,
+ borrowing_fee_usd: u256,
+ borrowing_fee_amount: u256,
+ borrowing_fee_receiver_factor: u256,
+ borrowing_fee_amount_for_fee_receiver: u256,
+ position_fee_factor: u256,
+ protocol_fee_amount: u256,
+ position_fee_receiver_factor: u256,
+ fee_receiver_amount: u256,
+ fee_amount_for_pool: u256,
+ position_fee_amount_for_pool: u256,
+ position_fee_amount: u256,
+ total_cost_amount: u256,
+ ui_fee_receiver_factor: u256,
+ ui_fee_amount: u256,
is_increase: bool
}
@@ -1052,34 +1037,34 @@ mod EventEmitter {
affiliate: ContractAddress,
trader: ContractAddress,
ui_fee_receiver: ContractAddress,
- collateral_token_price_min: u128,
- collateral_token_price_max: u128,
- trade_size_usd: u128,
- total_rebate_factor: u128,
- trader_discount_factor: u128,
- total_rebate_amount: u128,
- trader_discount_amount: u128,
- affiliate_reward_amount: u128,
- funding_fee_amount: u128,
- claimable_long_token_amount: u128,
- claimable_short_token_amount: u128,
- latest_funding_fee_amount_per_size: u128,
- latest_long_token_claimable_funding_amount_per_size: u128,
- latest_short_token_claimable_funding_amount_per_size: u128,
- borrowing_fee_usd: u128,
- borrowing_fee_amount: u128,
- borrowing_fee_receiver_factor: u128,
- borrowing_fee_amount_for_fee_receiver: u128,
- position_fee_factor: u128,
- protocol_fee_amount: u128,
- position_fee_receiver_factor: u128,
- fee_receiver_amount: u128,
- fee_amount_for_pool: u128,
- position_fee_amount_for_pool: u128,
- position_fee_amount: u128,
- total_cost_amount: u128,
- ui_fee_receiver_factor: u128,
- ui_fee_amount: u128,
+ collateral_token_price_min: u256,
+ collateral_token_price_max: u256,
+ trade_size_usd: u256,
+ total_rebate_factor: u256,
+ trader_discount_factor: u256,
+ total_rebate_amount: u256,
+ trader_discount_amount: u256,
+ affiliate_reward_amount: u256,
+ funding_fee_amount: u256,
+ claimable_long_token_amount: u256,
+ claimable_short_token_amount: u256,
+ latest_funding_fee_amount_per_size: u256,
+ latest_long_token_claimable_funding_amount_per_size: u256,
+ latest_short_token_claimable_funding_amount_per_size: u256,
+ borrowing_fee_usd: u256,
+ borrowing_fee_amount: u256,
+ borrowing_fee_receiver_factor: u256,
+ borrowing_fee_amount_for_fee_receiver: u256,
+ position_fee_factor: u256,
+ protocol_fee_amount: u256,
+ position_fee_receiver_factor: u256,
+ fee_receiver_amount: u256,
+ fee_amount_for_pool: u256,
+ position_fee_amount_for_pool: u256,
+ position_fee_amount: u256,
+ total_cost_amount: u256,
+ ui_fee_receiver_factor: u256,
+ ui_fee_amount: u256,
is_increase: bool
}
@@ -1098,24 +1083,24 @@ mod EventEmitter {
#[derive(Drop, starknet::Event)]
struct OrderUpdated {
key: felt252,
- size_delta_usd: u128,
- acceptable_price: u128,
- trigger_price: u128,
- min_output_amount: u128
+ size_delta_usd: u256,
+ acceptable_price: u256,
+ trigger_price: u256,
+ min_output_amount: u256
}
#[derive(Drop, starknet::Event)]
struct OrderSizeDeltaAutoUpdated {
key: felt252,
- size_delta_usd: u128,
- next_size_delta_usd: u128
+ size_delta_usd: u256,
+ next_size_delta_usd: u256
}
#[derive(Drop, starknet::Event)]
- struct OrderCollatDeltaAmountAutoUpdtd {
+ struct OrderCollateralDeltaAmountAutoUpdated {
key: felt252,
- collateral_delta_amount: u128,
- next_collateral_delta_amount: u128
+ collateral_delta_amount: u256,
+ next_collateral_delta_amount: u256
}
#[derive(Drop, starknet::Event)]
@@ -1137,9 +1122,9 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
affiliate: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1148,8 +1133,8 @@ mod EventEmitter {
token: ContractAddress,
affiliate: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1171,7 +1156,7 @@ mod EventEmitter {
}
#[derive(Drop, starknet::Event)]
- struct AfterWithdrawalCancelError {
+ struct AfterWithdrawalCancellationError {
key: felt252,
withdrawal: Withdrawal,
}
@@ -1199,7 +1184,7 @@ mod EventEmitter {
market: ContractAddress,
is_long: bool,
pnl_to_pool_factor: felt252,
- max_pnl_factor: u128,
+ max_pnl_factor: u256,
should_enable_adl: bool,
}
@@ -1228,7 +1213,7 @@ mod EventEmitter {
struct SetUint {
key: felt252,
data_bytes: Span,
- value: u128,
+ value: u256,
}
#[derive(Drop, starknet::Event)]
@@ -1307,9 +1292,9 @@ mod EventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
}
#[derive(Drop, starknet::Event)]
@@ -1317,9 +1302,9 @@ mod EventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
}
#[derive(Drop, starknet::Event)]
@@ -1337,28 +1322,28 @@ mod EventEmitter {
#[derive(Drop, starknet::Event)]
struct KeeperExecutionFee {
keeper: ContractAddress,
- execution_fee_amount: u128
+ execution_fee_amount: u256
}
#[derive(Drop, starknet::Event)]
struct ExecutionFeeRefund {
receiver: ContractAddress,
- refund_fee_amount: u128
+ refund_fee_amount: u256
}
#[derive(Drop, starknet::Event)]
struct MarketPoolValueInfoEvent {
market: ContractAddress,
market_pool_value_info: MarketPoolValueInfo,
- market_tokens_supply: u128
+ market_tokens_supply: u256
}
#[derive(Drop, starknet::Event)]
struct PoolAmountUpdated {
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1366,8 +1351,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1375,8 +1360,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1384,16 +1369,16 @@ mod EventEmitter {
market: ContractAddress,
is_long_token: bool,
virtual_market_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
struct VirtualPositionInventoryUpdated {
token: ContractAddress,
virtual_token_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: i256
}
#[derive(Drop, starknet::Event)]
@@ -1401,16 +1386,16 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
- struct CumulativeBorrowingFactorUpdatd {
+ struct CumulativeBorrowingFactorUpdated {
market: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1418,17 +1403,17 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
- struct ClaimableFundingPerSizeUpdatd {
+ struct ClaimableFundingAmountPerSizeUpdated {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1437,8 +1422,8 @@ mod EventEmitter {
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
}
#[derive(Drop, starknet::Event)]
@@ -1447,22 +1432,22 @@ mod EventEmitter {
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- time_key: u128,
- amount: u128,
- next_pool_value: u128
+ time_key: u256,
+ amount: u256,
+ next_pool_value: u256
}
#[derive(Drop, starknet::Event)]
struct UiFeeFactorUpdated {
account: ContractAddress,
- ui_fee_factor: u128
+ ui_fee_factor: u256
}
#[derive(Drop, starknet::Event)]
struct OraclePriceUpdate {
token: ContractAddress,
- min_price: u128,
- max_price: u128,
+ min_price: u256,
+ max_price: u256,
is_price_feed: bool
}
@@ -1489,20 +1474,20 @@ mod EventEmitter {
receiver: ContractAddress,
token_in: ContractAddress,
token_out: ContractAddress,
- token_in_price: u128,
- token_out_price: u128,
- amount_in: u128,
- amount_in_after_fees: u128,
- amount_out: u128,
- price_impact_usd: i128,
- price_impact_amount: i128
+ token_in_price: u256,
+ token_out_price: u256,
+ amount_in: u256,
+ amount_in_after_fees: u256,
+ amount_out: u256,
+ price_impact_usd: i256,
+ price_impact_amount: i256
}
#[derive(Drop, starknet::Event)]
struct SwapFeesCollected {
market: ContractAddress,
token: ContractAddress,
- token_price: u128,
+ token_price: u256,
action: felt252,
fees: SwapFees
}
@@ -1521,21 +1506,21 @@ mod EventEmitter {
#[derive(Drop, starknet::Event)]
struct SetTier {
- tier_id: u128,
- total_rebate: u128,
- discount_share: u128
+ tier_id: u256,
+ total_rebate: u256,
+ discount_share: u256
}
#[derive(Drop, starknet::Event)]
struct SetReferrerTier {
referrer: ContractAddress,
- tier_id: u128
+ tier_id: u256
}
#[derive(Drop, starknet::Event)]
struct SetReferrerDiscountShare {
referrer: ContractAddress,
- discount_share: u128
+ discount_share: u256
}
#[derive(Drop, starknet::Event)]
@@ -1566,7 +1551,7 @@ mod EventEmitter {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl EventEmitterImpl of super::IEventEmitter {
/// Emits the `ClaimableCollateralUpdated` event.
fn emit_claimable_collateral_updated(
@@ -1574,10 +1559,10 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- time_key: u128,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ time_key: u256,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
) {
self
.emit(
@@ -1593,9 +1578,9 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
) {
self
.emit(
@@ -1607,7 +1592,7 @@ mod EventEmitter {
/// Emits the `PositionImpactPoolAmountUpdated` event.
fn emit_position_impact_pool_amount_updated(
- ref self: ContractState, market: ContractAddress, delta: u128, next_value: u128,
+ ref self: ContractState, market: ContractAddress, delta: i256, next_value: u256,
) {
self.emit(PositionImpactPoolAmountUpdated { market, delta, next_value, });
}
@@ -1617,8 +1602,8 @@ mod EventEmitter {
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: i256,
+ next_value: u256,
) {
self.emit(SwapImpactPoolAmountUpdated { market, token, delta, next_value, });
}
@@ -1656,8 +1641,8 @@ mod EventEmitter {
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
+ delta: u256,
+ next_value: u256,
fee_type: felt252
) {
self.emit(ClaimableFeeAmountUpdated { market, token, delta, next_value, fee_type });
@@ -1669,9 +1654,9 @@ mod EventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128,
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256,
fee_type: felt252
) {
self
@@ -1687,7 +1672,7 @@ mod EventEmitter {
ref self: ContractState,
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128
+ fee_amount: u256
) {
self.emit(FeesClaimed { market, receiver, fee_amount });
}
@@ -1698,8 +1683,8 @@ mod EventEmitter {
ui_fee_receiver: ContractAddress,
market: ContractAddress,
receiver: ContractAddress,
- fee_amount: u128,
- next_pool_value: u128
+ fee_amount: u256,
+ next_pool_value: u256
) {
self
.emit(
@@ -1708,7 +1693,6 @@ mod EventEmitter {
}
/// Emits the `DepositCreated` event.
- #[inline(always)]
fn emit_deposit_created(ref self: ContractState, key: felt252, deposit: Deposit) {
self
.emit(
@@ -1736,9 +1720,9 @@ mod EventEmitter {
fn emit_deposit_executed(
ref self: ContractState,
key: felt252,
- long_token_amount: u128,
- short_token_amount: u128,
- received_market_tokens: u128
+ long_token_amount: u256,
+ short_token_amount: u256,
+ received_market_tokens: u256
) {
self
.emit(
@@ -1765,6 +1749,8 @@ mod EventEmitter {
receiver: withdrawal.receiver,
callback_contract: withdrawal.callback_contract,
market: withdrawal.market,
+ long_token_swap_path: withdrawal.long_token_swap_path,
+ short_token_swap_path: withdrawal.short_token_swap_path,
market_token_amount: withdrawal.market_token_amount,
min_long_token_amount: withdrawal.min_long_token_amount,
min_short_token_amount: withdrawal.min_short_token_amount,
@@ -1790,7 +1776,6 @@ mod EventEmitter {
/// Emits the `PositionIncrease` event.
/// # Arguments
/// * `params` - The position increase parameters.
- #[inline(always)]
fn emit_position_increase(ref self: ContractState, params: PositionIncreaseParams) {
self
.emit(
@@ -1802,7 +1787,7 @@ mod EventEmitter {
size_in_tokens: params.position.size_in_tokens,
collateral_amount: params.position.collateral_amount,
borrowing_factor: params.position.borrowing_factor,
- funding_fee_amount_per_pize: params.position.funding_fee_amount_per_size,
+ funding_fee_amount_per_size: params.position.funding_fee_amount_per_size,
long_token_claimable_funding_amount_per_size: params
.position
.long_token_claimable_funding_amount_per_size,
@@ -1838,14 +1823,13 @@ mod EventEmitter {
/// * `values` - The parameters linked to the decrease of collateral.
/// * `index_token_price` - The price of the index token.
/// * `collateral_token_price` - The price of the collateral token.
- #[inline(always)]
fn emit_position_decrease(
ref self: ContractState,
order_key: felt252,
position_key: felt252,
position: Position,
- size_delta_usd: u128,
- collateral_delta_amount: u128,
+ size_delta_usd: u256,
+ collateral_delta_amount: u256,
order_type: OrderType,
values: DecreasePositionCollateralValues,
index_token_price: Price,
@@ -1861,7 +1845,7 @@ mod EventEmitter {
size_in_tokens: position.size_in_tokens,
collateral_amount: position.collateral_amount,
borrowing_factor: position.borrowing_factor,
- funding_fee_amount_per_pize: position.funding_fee_amount_per_size,
+ funding_fee_amount_per_size: position.funding_fee_amount_per_size,
long_token_claimable_funding_amount_per_size: position
.long_token_claimable_funding_amount_per_size,
short_token_claimable_funding_amount_per_size: position
@@ -1902,10 +1886,10 @@ mod EventEmitter {
fn emit_order_updated(
ref self: ContractState,
key: felt252,
- size_delta_usd: u128,
- acceptable_price: u128,
- trigger_price: u128,
- min_output_amount: u128
+ size_delta_usd: u256,
+ acceptable_price: u256,
+ trigger_price: u256,
+ min_output_amount: u256
) {
self
.emit(
@@ -1917,21 +1901,21 @@ mod EventEmitter {
/// Emits the `OrderSizeDeltaAutoUpdated` event.
fn emit_order_size_delta_auto_updated(
- ref self: ContractState, key: felt252, size_delta_usd: u128, next_size_delta_usd: u128
+ ref self: ContractState, key: felt252, size_delta_usd: u256, next_size_delta_usd: u256
) {
self.emit(OrderSizeDeltaAutoUpdated { key, size_delta_usd, next_size_delta_usd });
}
- /// Emits the `OrderCollatDeltaAmountAutoUpdtd` event.
+ /// Emits the `OrderCollateralDeltaAmountAutoUpdated` event.
fn emit_order_collateral_delta_amount_auto_updated(
ref self: ContractState,
key: felt252,
- collateral_delta_amount: u128,
- next_collateral_delta_amount: u128
+ collateral_delta_amount: u256,
+ next_collateral_delta_amount: u256
) {
self
.emit(
- OrderCollatDeltaAmountAutoUpdtd {
+ OrderCollateralDeltaAmountAutoUpdated {
key, collateral_delta_amount, next_collateral_delta_amount
}
);
@@ -1946,9 +1930,9 @@ mod EventEmitter {
fn emit_insolvent_close_info(
ref self: ContractState,
order_key: felt252,
- position_collateral_amount: u128,
- base_pnl_usd: u128,
- remaining_cost_usd: u128
+ position_collateral_amount: u256,
+ base_pnl_usd: i256,
+ remaining_cost_usd: u256
) {
self
.emit(
@@ -1969,9 +1953,9 @@ mod EventEmitter {
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
- expected_amount: u128,
- amount_paid_in_collateral_token: u128,
- amount_paid_in_secondary_output_token: u128
+ expected_amount: u256,
+ amount_paid_in_collateral_token: u256,
+ amount_paid_in_secondary_output_token: u256
) {
self
.emit(
@@ -1992,7 +1976,7 @@ mod EventEmitter {
/// * `market` - The market where fees were collected.
/// * `collateral_token` - The collateral token.
/// * `trade_size_usd` - The trade size in usd.
- /// * `is_increase` - Wether it is an increase.
+ /// * `is_increase` - Whether it is an increase.
/// * `fees` - The struct storing position fees.
fn emit_position_fees_collected(
ref self: ContractState,
@@ -2000,7 +1984,7 @@ mod EventEmitter {
position_key: felt252,
market: ContractAddress,
collateral_token: ContractAddress,
- trade_size_usd: u128,
+ trade_size_usd: u256,
is_increase: bool,
fees: PositionFees
) {
@@ -2063,7 +2047,7 @@ mod EventEmitter {
/// * `market` - The market where fees were collected.
/// * `collateral_token` - The collateral token.
/// * `trade_size_usd` - The trade size in usd.
- /// * `is_increase` - Wether it is an increase.
+ /// * `is_increase` - Whether it is an increase.
/// * `fees` - The struct storing position fees.
fn emit_position_fees_info(
ref self: ContractState,
@@ -2071,7 +2055,7 @@ mod EventEmitter {
position_key: felt252,
market: ContractAddress,
collateral_token: ContractAddress,
- trade_size_usd: u128,
+ trade_size_usd: u256,
is_increase: bool,
fees: PositionFees
) {
@@ -2147,9 +2131,9 @@ mod EventEmitter {
market: ContractAddress,
token: ContractAddress,
affiliate: ContractAddress,
- delta: u128,
- next_value: u128,
- next_pool_value: u128
+ delta: u256,
+ next_value: u256,
+ next_pool_value: u256
) {
self
.emit(
@@ -2166,8 +2150,8 @@ mod EventEmitter {
token: ContractAddress,
affiliate: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
) {
self
.emit(
@@ -2202,7 +2186,7 @@ mod EventEmitter {
fn emit_after_withdrawal_cancellation_error(
ref self: ContractState, key: felt252, withdrawal: Withdrawal
) {
- self.emit(AfterWithdrawalCancelError { key, withdrawal });
+ self.emit(AfterWithdrawalCancellationError { key, withdrawal });
}
/// Emits the `AfterOrderExecutionError` event.
@@ -2225,7 +2209,7 @@ mod EventEmitter {
/// # Arguments
// * `market`- Address of the market for the ADL state update
// * `is_long`- Indicates the ADL state update is for the long or short side of the market
- // * `pnl_to_pool_factor`- The the ratio of PnL to pool value
+ // * `pnl_to_pool_factor`- The ratio of PnL to pool value
// * `max_pnl_factor`- The max PnL factor
// * `should_enable_adl`- Whether ADL was enabled or disabled
fn emit_adl_state_updated(
@@ -2233,7 +2217,7 @@ mod EventEmitter {
market: ContractAddress,
is_long: bool,
pnl_to_pool_factor: felt252,
- max_pnl_factor: u128,
+ max_pnl_factor: u256,
should_enable_adl: bool,
) {
self
@@ -2266,7 +2250,7 @@ mod EventEmitter {
/// Emits the `SetFelt252` event.
fn emit_set_uint(
- ref self: ContractState, key: felt252, data_bytes: Span, value: u128
+ ref self: ContractState, key: felt252, data_bytes: Span, value: u256
) {
self.emit(SetUint { key, data_bytes, value });
}
@@ -2366,9 +2350,9 @@ mod EventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
) {
self
.emit(
@@ -2389,9 +2373,9 @@ mod EventEmitter {
action_key: felt252,
token: ContractAddress,
price_feed: ContractAddress,
- price_feed_multiplier: u128,
- price_feed_heartbeat_duration: u128,
- stable_price: u128
+ price_feed_multiplier: u256,
+ price_feed_heartbeat_duration: u256,
+ stable_price: u256
) {
self
.emit(
@@ -2422,25 +2406,24 @@ mod EventEmitter {
/// Emits the `KeeperExecutionFee` event.
fn emit_keeper_execution_fee(
- ref self: ContractState, keeper: ContractAddress, execution_fee_amount: u128
+ ref self: ContractState, keeper: ContractAddress, execution_fee_amount: u256
) {
self.emit(KeeperExecutionFee { keeper, execution_fee_amount });
}
/// Emits the `ExecutionFeeRefund` event.
fn emit_execution_fee_refund(
- ref self: ContractState, receiver: ContractAddress, refund_fee_amount: u128
+ ref self: ContractState, receiver: ContractAddress, refund_fee_amount: u256
) {
self.emit(ExecutionFeeRefund { receiver, refund_fee_amount });
}
/// Emits the `MarketPoolValueInfo` event.
- #[inline(always)]
fn emit_market_pool_value_info(
ref self: ContractState,
market: ContractAddress,
market_pool_value_info: MarketPoolValueInfo,
- market_tokens_supply: u128
+ market_tokens_supply: u256
) {
self
.emit(
@@ -2455,8 +2438,8 @@ mod EventEmitter {
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
) {
self.emit(PoolAmountUpdated { market, token, delta, next_value });
}
@@ -2467,8 +2450,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
) {
self
.emit(
@@ -2484,8 +2467,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
) {
self.emit(OpenInterestUpdated { market, collateral_token, is_long, delta, next_value });
}
@@ -2496,8 +2479,8 @@ mod EventEmitter {
market: ContractAddress,
is_long_token: bool,
virtual_market_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
) {
self
.emit(
@@ -2512,8 +2495,8 @@ mod EventEmitter {
ref self: ContractState,
token: ContractAddress,
virtual_token_id: felt252,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: i256
) {
self
.emit(
@@ -2527,8 +2510,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: i256,
+ next_value: u256
) {
self
.emit(
@@ -2536,15 +2519,15 @@ mod EventEmitter {
);
}
- /// Emits the `CumulativeBorrowingFactorUpdatd` event.
+ /// Emits the `CumulativeBorrowingFactorUpdated` event.
fn emit_cumulative_borrowing_factor_updated(
ref self: ContractState,
market: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
) {
- self.emit(CumulativeBorrowingFactorUpdatd { market, is_long, delta, next_value });
+ self.emit(CumulativeBorrowingFactorUpdated { market, is_long, delta, next_value });
}
/// Emits the `FundingFeeAmountPerSizeUpdated` event.
@@ -2553,8 +2536,8 @@ mod EventEmitter {
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
) {
self
.emit(
@@ -2564,32 +2547,32 @@ mod EventEmitter {
);
}
- /// Emits the `ClaimableFundingPerSizeUpdatd` event.
+ /// Emits the `ClaimableFundingAmountPerSizeUpdated` event.
fn emit_claimable_funding_amount_per_size_updated(
ref self: ContractState,
market: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- delta: u128,
- next_value: u128
+ delta: u256,
+ next_value: u256
) {
self
.emit(
- ClaimableFundingPerSizeUpdatd {
+ ClaimableFundingAmountPerSizeUpdated {
market, collateral_token, is_long, delta, next_value
}
);
}
/// Emits the `FundingFeesClaimed` event.
- fn emit_founding_fees_claimed(
+ fn emit_funding_fees_claimed(
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- amount: u128,
- next_pool_value: u128
+ amount: u256,
+ next_pool_value: u256
) {
self
.emit(
@@ -2604,9 +2587,9 @@ mod EventEmitter {
token: ContractAddress,
account: ContractAddress,
receiver: ContractAddress,
- time_key: u128,
- amount: u128,
- next_pool_value: u128
+ time_key: u256,
+ amount: u256,
+ next_pool_value: u256
) {
self
.emit(
@@ -2618,7 +2601,7 @@ mod EventEmitter {
/// Emits the `UiFeeFactorUpdated` event.
fn emit_ui_fee_factor_updated(
- ref self: ContractState, account: ContractAddress, ui_fee_factor: u128
+ ref self: ContractState, account: ContractAddress, ui_fee_factor: u256
) {
self.emit(UiFeeFactorUpdated { account, ui_fee_factor });
}
@@ -2627,8 +2610,8 @@ mod EventEmitter {
fn emit_oracle_price_update(
ref self: ContractState,
token: ContractAddress,
- min_price: u128,
- max_price: u128,
+ min_price: u256,
+ max_price: u256,
is_price_feed: bool
) {
self.emit(OraclePriceUpdate { token, min_price, max_price, is_price_feed });
@@ -2660,13 +2643,13 @@ mod EventEmitter {
receiver: ContractAddress,
token_in: ContractAddress,
token_out: ContractAddress,
- token_in_price: u128,
- token_out_price: u128,
- amount_in: u128,
- amount_in_after_fees: u128,
- amount_out: u128,
- price_impact_usd: i128,
- price_impact_amount: i128
+ token_in_price: u256,
+ token_out_price: u256,
+ amount_in: u256,
+ amount_in_after_fees: u256,
+ amount_out: u256,
+ price_impact_usd: i256,
+ price_impact_amount: i256
) {
self
.emit(
@@ -2688,12 +2671,11 @@ mod EventEmitter {
}
/// Emits the `SwapFeesCollected` event.
- #[inline(always)]
fn emit_swap_fees_collected(
ref self: ContractState,
market: ContractAddress,
token: ContractAddress,
- token_price: u128,
+ token_price: u256,
action: felt252,
fees: SwapFees
) {
@@ -2703,8 +2685,8 @@ mod EventEmitter {
fn emit_oracle_price_updated(
ref self: ContractState,
token: ContractAddress,
- min_price: u128,
- max_price: u128,
+ min_price: u256,
+ max_price: u256,
is_price_feed: bool
) {
self.emit(OraclePriceUpdate { token, min_price, max_price, is_price_feed });
@@ -2715,19 +2697,19 @@ mod EventEmitter {
}
fn emit_set_tier(
- ref self: ContractState, tier_id: u128, total_rebate: u128, discount_share: u128
+ ref self: ContractState, tier_id: u256, total_rebate: u256, discount_share: u256
) {
self.emit(SetTier { tier_id, total_rebate, discount_share });
}
fn emit_set_referrer_tier(
- ref self: ContractState, referrer: ContractAddress, tier_id: u128
+ ref self: ContractState, referrer: ContractAddress, tier_id: u256
) {
self.emit(SetReferrerTier { referrer, tier_id });
}
fn emit_set_referrer_discount_share(
- ref self: ContractState, referrer: ContractAddress, discount_share: u128
+ ref self: ContractState, referrer: ContractAddress, discount_share: u256
) {
self.emit(SetReferrerDiscountShare { referrer, discount_share });
}
diff --git a/src/event/event_utils.cairo b/src/event/event_utils.cairo
index ee9c8ebe..702d419b 100644
--- a/src/event/event_utils.cairo
+++ b/src/event/event_utils.cairo
@@ -1,5 +1,185 @@
-#[derive(Drop, starknet::Store, Serde)]
+use starknet::{
+ get_caller_address, ContractAddress, Felt252TryIntoContractAddress, ContractAddressIntoFelt252,
+ contract_address_const
+};
+use array::ArrayTrait;
+use satoru::utils::i256::i256;
+use traits::Default;
+use satoru::utils::traits::ContractAddressDefault;
+
+use satoru::utils::serializable_dict::{SerializableFelt252Dict, SerializableFelt252DictTrait};
+
+use alexandria_data_structures::array_ext::SpanTraitExt;
+
+
+//
+// NEEDED IMPLEMENTATIONS FOR LOGDATA TYPES
+//
+
+impl Felt252IntoBool of Into {
+ fn into(self: felt252) -> bool {
+ let as_u256: u256 = self.into();
+ as_u256 > 0
+ }
+}
+
+impl Felt252IntoContractAddress of Into {
+ fn into(self: felt252) -> ContractAddress {
+ Felt252TryIntoContractAddress::try_into(self).expect('contractaddress overflow')
+ }
+}
+
+// workaround for serialization to work with u256
+impl U256IntoFelt252 of Into {
+ fn into(self: u256) -> felt252 {
+ self.high.into() * 0x100000000000000000000000000000000_felt252 + self.low.into()
+ }
+}
+
+impl I256252DictValue of Felt252DictValue {
+ fn zero_default() -> i256 nopanic {
+ i256 { mag: 0, sign: false }
+ }
+}
+
+impl U256252DictValue of Felt252DictValue {
+ fn zero_default() -> u256 nopanic {
+ u256 { high: 0, low: 0 }
+ }
+}
+
+impl ContractAddressDictValue of Felt252DictValue {
+ fn zero_default() -> ContractAddress nopanic {
+ contract_address_const::<0>()
+ }
+}
+
+//
+// LOG DATA IMPLEMENTATION
+//
+
+//TODO Switch the append with a set in the functions when its available
+#[derive(Default, Serde, Destruct)]
struct EventLogData {
- cant_be_empty: u128, // remove
+ cant_be_empty: u256, // remove
// TODO
}
+
+#[derive(Default, Destruct)]
+struct LogData {
+ address_dict: SerializableFelt252Dict,
+ uint_dict: SerializableFelt252Dict,
+ int_dict: SerializableFelt252Dict,
+ bool_dict: SerializableFelt252Dict,
+ felt252_dict: SerializableFelt252Dict,
+ string_dict: SerializableFelt252Dict
+}
+
+/// Number of dicts presents in LogData
+const DICTS_IN_LOGDATA: usize = 6;
+
+/// When serializing dicts into a unique Array, this is the value that will
+/// be used to recognized a separation between two dicts.
+const END_OF_DICT: felt252 = '______';
+
+#[generate_trait]
+impl LogDataImpl of LogDataTrait {
+ /// Serializes all the sub-dicts of LogData & append all of them into a new felt252 array
+ fn serialize(ref self: LogData, ref output: Array) {
+ let mut serialized_dicts: Array> = array![
+ self.address_dict.serialize_into(),
+ self.uint_dict.serialize_into(),
+ self.int_dict.serialize_into(),
+ self.bool_dict.serialize_into(),
+ self.felt252_dict.serialize_into(),
+ self.string_dict.serialize_into()
+ ];
+ let mut span_arrays = serialized_dicts.span();
+ loop {
+ match span_arrays.pop_front() {
+ Option::Some(arr) => {
+ let mut sub_array_span = arr.span();
+ loop {
+ match sub_array_span.pop_front() {
+ Option::Some(v) => { output.append(*v); },
+ Option::None => { break; }
+ };
+ };
+ output.append(END_OF_DICT);
+ },
+ Option::None => { break; }
+ };
+ };
+ }
+
+ /// Serializes all the sub-dicts of LogData & return the serialized data
+ fn serialize_into(ref self: LogData) -> Array {
+ let mut serialized_data: Array = array![];
+ self.serialize(ref serialized_data);
+ serialized_data
+ }
+
+ /// Deserialize all the sub-dicts serialized into a LogData
+ fn deserialize(ref serialized: Span) -> Option {
+ // There should be the right amount of dictionaries serialized
+ if serialized.occurrences_of(END_OF_DICT) != DICTS_IN_LOGDATA {
+ panic_with_felt252('serialized format error');
+ }
+
+ // Deserialize all dicts one by one
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let address_dict = SerializableFelt252DictTrait::<
+ ContractAddress
+ >::deserialize(ref serialized_dict)
+ .expect('deserialize err address');
+
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let uint_dict = SerializableFelt252DictTrait::::deserialize(ref serialized_dict)
+ .expect('deserialize err uint');
+
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let int_dict = SerializableFelt252DictTrait::::deserialize(ref serialized_dict)
+ .expect('deserialize err int');
+
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let bool_dict = SerializableFelt252DictTrait::::deserialize(ref serialized_dict)
+ .expect('deserialize err bool');
+
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let felt252_dict = SerializableFelt252DictTrait::::deserialize(ref serialized_dict)
+ .expect('deserialize err felt252');
+
+ let mut serialized_dict = get_next_dict_serialized(ref serialized);
+ let string_dict = SerializableFelt252DictTrait::::deserialize(ref serialized_dict)
+ .expect('deserialize err string');
+
+ // Create the LogData struct with every dicts
+ let log_data: LogData = LogData {
+ address_dict, uint_dict, int_dict, bool_dict, felt252_dict, string_dict
+ };
+
+ Option::Some(log_data)
+ }
+}
+
+
+//
+// UTILITY FUNCTION
+//
+
+/// Pop every elements from the span until the next occurrences of END_OF_DICT or
+/// the end of the Span and return those values in a Span.
+fn get_next_dict_serialized(ref serialized: Span) -> Span {
+ let mut dict_data: Array = array![];
+ loop {
+ match serialized.pop_front() {
+ Option::Some(v) => { if *v == END_OF_DICT {
+ break;
+ } else {
+ dict_data.append(*v);
+ } },
+ Option::None => { break; }
+ };
+ };
+ dict_data.span()
+}
diff --git a/src/exchange/adl_handler.cairo b/src/exchange/adl_handler.cairo
index 500d0761..a8589f1a 100644
--- a/src/exchange/adl_handler.cairo
+++ b/src/exchange/adl_handler.cairo
@@ -10,6 +10,8 @@ use starknet::ContractAddress;
// Local imports.
use satoru::oracle::oracle_utils::SetPricesParams;
+use satoru::utils::i256::i256;
+
// *************************************************************************
// Interface of the `AdlHandler` contract.
@@ -19,7 +21,7 @@ trait IAdlHandler {
/// Checks the ADL state to update the isAdlEnabled flag.
/// # Arguments
/// * `market` - The market to check.
- /// * `is_long` - Wether to check long or short side.
+ /// * `is_long` - Whether to check long or short side.
/// * `oracle_params` - The oracle set price parameters used to set price
/// before performing checks
fn update_adl_state(
@@ -38,7 +40,7 @@ trait IAdlHandler {
/// position profit, this is not implemented within the contracts at the moment.
/// # Arguments
/// * `market` - The market to check.
- /// * `is_long` - Wether to check long or short side.
+ /// * `is_long` - Whether to check long or short side.
/// * `oracle_params` - The oracle set price parameters used to set price
/// before performing adl.
fn execute_adl(
@@ -47,7 +49,7 @@ trait IAdlHandler {
market_address: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- size_delta_usd: u128,
+ size_delta_usd: u256,
oracle_params: SetPricesParams
);
}
@@ -75,6 +77,7 @@ mod AdlHandler {
use satoru::exchange::base_order_handler::BaseOrderHandler::{
data_store::InternalContractMemberStateTrait as DataStoreStateTrait,
event_emitter::InternalContractMemberStateTrait as EventEmitterStateTrait,
+ order_utils::InternalContractMemberStateTrait as OrderUtilsTrait,
oracle::InternalContractMemberStateTrait as OracleStateTrait,
InternalTrait as BaseOrderHandleInternalTrait,
};
@@ -89,33 +92,36 @@ mod AdlHandler {
use satoru::order::{
order::{SecondaryOrderType, OrderType, Order},
order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait},
- base_order_utils::{ExecuteOrderParams, ExecuteOrderParamsContracts}, order_utils
+ base_order_utils::{ExecuteOrderParams, ExecuteOrderParamsContracts},
+ order_utils::{IOrderUtilsDispatcher}
};
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
use satoru::swap::swap_handler::{ISwapHandlerDispatcher, ISwapHandlerDispatcherTrait};
- use satoru::utils::store_arrays::StoreU64Array;
+ use satoru::utils::{store_arrays::StoreU64Array, calc::to_signed};
+ use satoru::utils::i256::i256;
+
/// ExecuteAdlCache struct used in execute_adl.
#[derive(Drop, Serde)]
struct ExecuteAdlCache {
/// The starting gas to execute adl.
- starting_gas: u128,
+ starting_gas: u256,
/// The min oracles block numbers.
min_oracle_block_numbers: Array,
/// The max oracles block numbers.
max_oracle_block_numbers: Array,
/// The key of the adl to execute.
key: felt252,
- /// Wether adl should be allowed, depending on pnl state.
+ /// Whether adl should be allowed, depending on pnl state.
should_allow_adl: bool,
/// The maximum pnl factor to allow adl.
- max_pnl_factor_for_adl: u128,
+ max_pnl_factor_for_adl: u256,
/// The factor between pnl and pool.
- pnl_to_pool_factor: u128, // TODO i128 when it derive Store
+ pnl_to_pool_factor: i256,
/// The new factor between pnl and pool.
- next_pnl_to_pool_factor: u128, // TODO i128 when it derive Store
+ next_pnl_to_pool_factor: i256,
/// The minimal pnl factor for adl.
- min_pnl_factor_for_adl: u128
+ min_pnl_factor_for_adl: u256
}
// *************************************************************************
@@ -147,7 +153,7 @@ mod AdlHandler {
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
referral_storage_address: ContractAddress,
- order_handler_address: ContractAddress
+ order_utils_address: ContractAddress
) {
let mut state: BaseOrderHandler::ContractState =
BaseOrderHandler::unsafe_new_contract_state();
@@ -159,14 +165,16 @@ mod AdlHandler {
order_vault_address,
oracle_address,
swap_handler_address,
- referral_storage_address
+ referral_storage_address,
+ order_utils_address
);
+ self.order_utils.write(IOrderUtilsDispatcher { contract_address: order_utils_address });
}
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl AdlHandlerImpl of super::IAdlHandler {
fn update_adl_state(
ref self: ContractState,
@@ -197,7 +205,7 @@ mod AdlHandler {
market_address: ContractAddress,
collateral_token: ContractAddress,
is_long: bool,
- size_delta_usd: u128,
+ size_delta_usd: u256,
oracle_params: oracle_utils::SetPricesParams
) {
let mut cache = ExecuteAdlCache {
@@ -207,8 +215,8 @@ mod AdlHandler {
key: 0,
should_allow_adl: false,
max_pnl_factor_for_adl: 0,
- pnl_to_pool_factor: 0,
- next_pnl_to_pool_factor: 0,
+ pnl_to_pool_factor: Zeroable::zero(),
+ next_pnl_to_pool_factor: Zeroable::zero(),
min_pnl_factor_for_adl: 0
};
@@ -278,7 +286,7 @@ mod AdlHandler {
)
);
- order_utils::execute_order(params);
+ base_order_handler_state.order_utils.read().execute_order_utils(params);
// validate that the ratio of pending pnl to pool value was decreased
cache
@@ -292,7 +300,8 @@ mod AdlHandler {
.min_pnl_factor_for_adl =
market_utils::get_min_pnl_factor_after_adl(data_store, market_address, is_long);
assert(
- cache.next_pnl_to_pool_factor > cache.min_pnl_factor_for_adl, 'pnl overcorrected'
+ cache.next_pnl_to_pool_factor > to_signed(cache.min_pnl_factor_for_adl, true),
+ 'pnl overcorrected'
);
}
}
diff --git a/src/exchange/base_order_handler.cairo b/src/exchange/base_order_handler.cairo
index 88188982..6db1b2b9 100644
--- a/src/exchange/base_order_handler.cairo
+++ b/src/exchange/base_order_handler.cairo
@@ -6,7 +6,7 @@
// Core lib imports.
use core::traits::Into;
-use starknet::ContractAddress;
+use starknet::{ContractAddress, contract_address_const, ClassHash};
use satoru::oracle::oracle_utils::SetPricesParams;
use satoru::order::{order::SecondaryOrderType, base_order_utils::ExecuteOrderParams};
@@ -33,7 +33,11 @@ trait IBaseOrderHandler {
order_vault_address: ContractAddress,
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
- referral_storage_address: ContractAddress
+ referral_storage_address: ContractAddress,
+ order_utils_class_hash: ClassHash,
+ increase_order_utils_class_hash: ClassHash,
+ decrease_order_utils_class_hash: ClassHash,
+ swap_order_utils_class_hash: ClassHash,
);
}
@@ -44,16 +48,20 @@ mod BaseOrderHandler {
// *************************************************************************
// Core lib imports.
+ use core::option::OptionTrait;
use core::zeroable::Zeroable;
use core::traits::Into;
- use starknet::{get_caller_address, ContractAddress, contract_address_const};
+ use starknet::{get_caller_address, ContractAddress, contract_address_const, ClassHash};
- use debug::PrintTrait;
use result::ResultTrait;
// Local imports.
use super::IBaseOrderHandler;
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
+ use satoru::role::role_module::{
+ IRoleModuleDispatcher, IRoleModuleDispatcherTrait, RoleModule, IRoleModule
+ };
+
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
use satoru::oracle::{
@@ -62,9 +70,13 @@ mod BaseOrderHandler {
oracle_utils::{SetPricesParams, get_uncompacted_oracle_block_numbers},
};
use satoru::order::{
- order::{SecondaryOrderType, OrderType, Order, DecreasePositionSwapType},
+ error::OrderError, order::{SecondaryOrderType, OrderType, Order, DecreasePositionSwapType},
order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait},
- base_order_utils::{ExecuteOrderParams, ExecuteOrderParamsContracts}, order_store_utils,
+ base_order_utils::{ExecuteOrderParams, ExecuteOrderParamsContracts},
+ order_utils::IOrderUtilsLibraryDispatcher,
+ increase_order_utils::IIncreaseOrderUtilsLibraryDispatcher,
+ decrease_order_utils::IDecreaseOrderUtilsLibraryDispatcher,
+ swap_order_utils::ISwapOrderUtilsLibraryDispatcher
};
use satoru::swap::swap_handler::{ISwapHandlerDispatcher, ISwapHandlerDispatcherTrait};
use satoru::exchange::error::ExchangeError;
@@ -92,7 +104,15 @@ mod BaseOrderHandler {
/// Interface to interact with the `Oracle` contract.
oracle: IOracleDispatcher,
/// Interface to interact with the `ReferralStorage` contract.
- referral_storage: IReferralStorageDispatcher
+ referral_storage: IReferralStorageDispatcher,
+ /// Interface to interact with the `OrderUtils` lib.
+ order_utils_lib: IOrderUtilsLibraryDispatcher,
+ /// Interface to interact with the `IncreaseOrderUtils` lib.
+ increase_order_utils_lib: IIncreaseOrderUtilsLibraryDispatcher,
+ /// Interface to interact with the `DecreaseOrderUtils` lib.
+ decrease_order_utils_lib: IDecreaseOrderUtilsLibraryDispatcher,
+ /// Interface to interact with the `SwapOrderUtils` lib.
+ swap_order_utils_lib: ISwapOrderUtilsLibraryDispatcher
}
// *************************************************************************
@@ -117,7 +137,11 @@ mod BaseOrderHandler {
order_vault_address: ContractAddress,
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
- referral_storage_address: ContractAddress
+ referral_storage_address: ContractAddress,
+ order_utils_class_hash: ClassHash,
+ increase_order_utils_class_hash: ClassHash,
+ decrease_order_utils_class_hash: ClassHash,
+ swap_order_utils_class_hash: ClassHash,
) {
self
.initialize(
@@ -127,7 +151,11 @@ mod BaseOrderHandler {
order_vault_address,
oracle_address,
swap_handler_address,
- referral_storage_address
+ referral_storage_address,
+ order_utils_class_hash,
+ increase_order_utils_class_hash,
+ decrease_order_utils_class_hash,
+ swap_order_utils_class_hash
);
}
@@ -135,7 +163,7 @@ mod BaseOrderHandler {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl BaseOrderHandlerImpl of super::IBaseOrderHandler {
fn initialize(
ref self: ContractState,
@@ -145,7 +173,11 @@ mod BaseOrderHandler {
order_vault_address: ContractAddress,
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
- referral_storage_address: ContractAddress
+ referral_storage_address: ContractAddress,
+ order_utils_class_hash: ClassHash,
+ increase_order_utils_class_hash: ClassHash,
+ decrease_order_utils_class_hash: ClassHash,
+ swap_order_utils_class_hash: ClassHash,
) {
// Make sure the contract is not already initialized.
assert(
@@ -154,6 +186,7 @@ mod BaseOrderHandler {
);
self.data_store.write(IDataStoreDispatcher { contract_address: data_store_address });
self.role_store.write(IRoleStoreDispatcher { contract_address: role_store_address });
+
self
.event_emitter
.write(IEventEmitterDispatcher { contract_address: event_emitter_address });
@@ -165,6 +198,28 @@ mod BaseOrderHandler {
self
.referral_storage
.write(IReferralStorageDispatcher { contract_address: referral_storage_address });
+ self
+ .order_utils_lib
+ .write(IOrderUtilsLibraryDispatcher { class_hash: order_utils_class_hash });
+ self
+ .increase_order_utils_lib
+ .write(
+ IIncreaseOrderUtilsLibraryDispatcher {
+ class_hash: increase_order_utils_class_hash
+ }
+ );
+ self
+ .decrease_order_utils_lib
+ .write(
+ IDecreaseOrderUtilsLibraryDispatcher {
+ class_hash: decrease_order_utils_class_hash
+ }
+ );
+ self
+ .swap_order_utils_lib
+ .write(
+ ISwapOrderUtilsLibraryDispatcher { class_hash: swap_order_utils_class_hash }
+ );
}
}
@@ -175,7 +230,7 @@ mod BaseOrderHandler {
impl InternalImpl of InternalTrait {
/// Get the BaseOrderUtils.ExecuteOrderParams to execute an order.
/// # Arguments
- /// * `key` - The the key of the order to execute.
+ /// * `key` - The key of the order to execute.
/// * `oracle_params` - The set price parameters for oracle.
/// * `keeper` - The keeper executing the order.
/// * `starting_gas` - The starting gas.
@@ -184,12 +239,13 @@ mod BaseOrderHandler {
key: felt252,
oracle_params: SetPricesParams,
keeper: ContractAddress,
- starting_gas: u128,
+ starting_gas: u256,
secondary_order_type: SecondaryOrderType
) -> ExecuteOrderParams {
let data_store = self.data_store.read();
- let order = order_store_utils::get(data_store, key);
+ let order = data_store.get_order(key);
+
let swap_path_markets = market_utils::get_swap_path_markets(
data_store, order.swap_path
);
@@ -210,7 +266,7 @@ mod BaseOrderHandler {
oracle_params.compacted_max_oracle_block_numbers.span(), oracle_params.tokens.len()
);
- let address_zero = 0.try_into().unwrap();
+ let address_zero = contract_address_const::<0>();
let mut market = Default::default();
diff --git a/src/exchange/deleted_funtions b/src/exchange/deleted_funtions
new file mode 100644
index 00000000..3b5a8e19
--- /dev/null
+++ b/src/exchange/deleted_funtions
@@ -0,0 +1,165 @@
+// fn update_order(
+ // ref self: ContractState,
+ // key: felt252,
+ // size_delta_usd: u256,
+ // acceptable_price: u256,
+ // trigger_price: u256,
+ // min_output_amount: u256,
+ // order: Order
+ // ) -> Order {
+ // // Check only controller.
+ // let role_module_state = RoleModule::unsafe_new_contract_state();
+ // role_module_state.only_controller();
+
+ // // Fetch data store.
+ // let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
+ // let data_store = base_order_handler_state.data_store.read();
+ // let event_emitter = base_order_handler_state.event_emitter.read();
+
+ // global_reentrancy_guard::non_reentrant_before(data_store);
+
+ // // Validate feature.
+ // feature_utils::validate_feature(
+ // data_store,
+ // keys::update_order_feature_disabled_key(get_contract_address(), order.order_type)
+ // );
+
+ // assert(base_order_utils::is_market_order(order.order_type), 'OrderNotUpdatable');
+
+ // let mut updated_order = order.clone();
+ // updated_order.size_delta_usd = size_delta_usd;
+ // updated_order.trigger_price = trigger_price;
+ // updated_order.acceptable_price = acceptable_price;
+ // updated_order.min_output_amount = min_output_amount;
+ // updated_order.is_frozen = false;
+
+ // // Allow topping up of execution fee as frozen orders will have execution fee reduced.
+ // let fee_token = token_utils::fee_token(data_store);
+ // let order_vault = base_order_handler_state.order_vault.read();
+ // let received_fee_token = order_vault.record_transfer_in(fee_token);
+ // updated_order.execution_fee = received_fee_token;
+
+ // let estimated_gas_limit = gas_utils::estimate_execute_order_gas_limit(
+ // data_store, @updated_order
+ // );
+ // gas_utils::validate_execution_fee(
+ // data_store, estimated_gas_limit, updated_order.execution_fee
+ // );
+
+ // updated_order.touch();
+
+ // base_order_utils::validate_non_empty_order(@updated_order);
+
+ // data_store.set_order(key, updated_order);
+ // event_emitter
+ // .emit_order_updated(
+ // key, size_delta_usd, acceptable_price, trigger_price, min_output_amount
+ // );
+
+ // global_reentrancy_guard::non_reentrant_after(data_store);
+
+ // updated_order
+ // }
+
+ // fn cancel_order(ref self: ContractState, key: felt252) {
+ // let starting_gas: u256 = 0; // TODO: Get starting gas from Cairo.
+
+ // // Check only controller.
+ // let role_module_state = RoleModule::unsafe_new_contract_state();
+ // role_module_state.only_controller();
+
+ // // Fetch data store.
+ // let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
+ // let data_store = base_order_handler_state.data_store.read();
+
+ // global_reentrancy_guard::non_reentrant_before(data_store);
+
+ // let order = data_store.get_order(key);
+
+ // // Validate feature.
+ // feature_utils::validate_feature(
+ // data_store,
+ // keys::cancel_order_feature_disabled_key(get_contract_address(), order.order_type)
+ // );
+
+ // if base_order_utils::is_market_order(order.order_type) {
+ // exchange_utils::validate_request_cancellation(
+ // data_store, order.updated_at_block, 'Order'
+ // )
+ // }
+
+ // order_utils::cancel_order(
+ // data_store,
+ // base_order_handler_state.event_emitter.read(),
+ // base_order_handler_state.order_vault.read(),
+ // key,
+ // order.account,
+ // starting_gas,
+ // keys::user_initiated_cancel(),
+ // ArrayTrait::::new(),
+ // );
+
+ // global_reentrancy_guard::non_reentrant_after(data_store);
+ // }
+
+
+ internal
+
+/// Handles error from order.
+ /// # Arguments
+ /// * `key` - The key of the deposit to handle error for.
+ /// * `starting_gas` - The starting gas of the transaction.
+ /// * `reason` - The reason of the error.
+ // fn handle_order_error(
+ // self: @ContractState, key: felt252, starting_gas: u256, reason_bytes: Array
+ // ) {
+ // let error_selector = error_utils::get_error_selector_from_data(reason_bytes.span());
+
+ // let mut base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
+ // let data_store = base_order_handler_state.data_store.read();
+
+ // let order = data_store.get_order(key);
+ // // let is_market_order = base_order_utils::is_market_order(order.order_type);
+
+ // if (oracle_utils::is_oracle_error(error_selector)
+ // || order.is_frozen
+ // // || (!is_market_order && error_selector == PositionError::EMPTY_POSITION)
+ // || error_selector == OrderError::EMPTY_ORDER
+ // || error_selector == FeatureError::DISABLED_FEATURE
+ // || error_selector == OrderError::INVALID_KEEPER_FOR_FROZEN_ORDER
+ // || error_selector == OrderError::UNSUPPORTED_ORDER_TYPE
+ // || error_selector == OrderError::INVALID_ORDER_PRICES) {
+ // assert(false, error_utils::revert_with_custom_error(reason_bytes.span()))
+ // }
+
+ // let reason = error_utils::get_revert_message(reason_bytes.span());
+
+ // if (is_market_order
+ // || error_selector == MarketError::INVALID_POSITION_MARKET
+ // || error_selector == MarketError::INVALID_COLLATERAL_TOKEN_FOR_MARKET
+ // || error_selector == PositionError::INVALID_POSITION_SIZE_VALUES) {
+ // order_utils::cancel_order(
+ // data_store,
+ // base_order_handler_state.event_emitter.read(),
+ // base_order_handler_state.order_vault.read(),
+ // key,
+ // order.account,
+ // starting_gas,
+ // reason,
+ // reason_bytes,
+ // );
+ // return ();
+ // }
+
+ // order_utils::freeze_order(
+ // data_store,
+ // base_order_handler_state.event_emitter.read(),
+ // base_order_handler_state.order_vault.read(),
+ // key,
+ // get_caller_address(),
+ // starting_gas,
+ // reason,
+ // reason_bytes
+ // );
+ // }
+
diff --git a/src/exchange/deposit_handler.cairo b/src/exchange/deposit_handler.cairo
index d0d2ca38..c128c4d5 100644
--- a/src/exchange/deposit_handler.cairo
+++ b/src/exchange/deposit_handler.cairo
@@ -66,16 +66,16 @@ mod DepositHandler {
// *************************************************************************
// Core lib imports.
- use starknet::ContractAddress;
-
+ use starknet::{get_caller_address, get_contract_address, ContractAddress};
// Local imports.
use super::IDepositHandler;
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
+ use satoru::role::role_module::{RoleModule, IRoleModule};
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
use satoru::oracle::{
- oracle::{IOracleDispatcher, IOracleDispatcherTrait},
+ oracle::{IOracleDispatcher, IOracleDispatcherTrait}, oracle_modules,
oracle_modules::{with_oracle_prices_before, with_oracle_prices_after},
oracle_utils::{SetPricesParams, SimulatePricesParams}
};
@@ -86,6 +86,14 @@ mod DepositHandler {
deposit_utils::CreateDepositParams,
deposit_vault::{IDepositVaultDispatcher, IDepositVaultDispatcherTrait}
};
+ use satoru::deposit::deposit_utils;
+ use satoru::feature::feature_utils;
+ use satoru::gas::gas_utils;
+ use satoru::data::keys;
+ use satoru::exchange::exchange_utils;
+ use satoru::deposit::execute_deposit_utils;
+ use satoru::oracle::oracle_utils;
+ use satoru::utils::global_reentrancy_guard;
// *************************************************************************
// STORAGE
@@ -139,26 +147,105 @@ mod DepositHandler {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl DepositHandlerImpl of super::IDepositHandler {
fn create_deposit(
ref self: ContractState, account: ContractAddress, params: CreateDepositParams
) -> felt252 {
- // TODO
- 0
+ let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
+ IRoleModule::only_controller(@state);
+
+ let data_store = self.data_store.read();
+ global_reentrancy_guard::non_reentrant_before(data_store);
+
+ feature_utils::validate_feature(
+ self.data_store.read(),
+ keys::create_deposit_feature_disabled_key(get_contract_address())
+ );
+
+ let key = deposit_utils::create_deposit(
+ self.data_store.read(),
+ self.event_emitter.read(),
+ self.deposit_vault.read(),
+ account,
+ params
+ );
+
+ global_reentrancy_guard::non_reentrant_after(data_store);
+
+ key
}
- fn cancel_deposit(ref self: ContractState, key: felt252) { // TODO
+ fn cancel_deposit(ref self: ContractState, key: felt252) {
+ let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
+ IRoleModule::only_controller(@state);
+
+ let data_store = self.data_store.read();
+ global_reentrancy_guard::non_reentrant_before(data_store);
+
+ // let starting_gas = gas_left();
+
+ let deposit = data_store.get_deposit(key);
+
+ feature_utils::validate_feature(
+ data_store, keys::cancel_deposit_feature_disabled_key(get_contract_address())
+ );
+ exchange_utils::validate_request_cancellation(
+ data_store, deposit.updated_at_block, 'Deposit'
+ );
+
+ deposit_utils::cancel_deposit(
+ data_store,
+ self.event_emitter.read(),
+ self.deposit_vault.read(),
+ key,
+ deposit.account,
+ 0, //starting_gas
+ keys::user_initiated_cancel(),
+ array!['']
+ );
+
+ global_reentrancy_guard::non_reentrant_after(data_store);
}
- fn execute_deposit(
- ref self: ContractState, key: felt252, oracle_params: SetPricesParams
- ) { // TODO
+ fn execute_deposit(ref self: ContractState, key: felt252, oracle_params: SetPricesParams) {
+ let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
+ IRoleModule::only_order_keeper(@state);
+
+ let data_store = self.data_store.read();
+ let oracle = self.oracle.read();
+ let event_emitter = self.event_emitter.read();
+ // global_reentrancy_guard::non_reentrant_before(data_store);
+ oracle_modules::with_oracle_prices_before(
+ oracle, data_store, event_emitter, @oracle_params
+ );
+
+ // let starting_gas = gas_left();
+ let execution_gas = gas_utils::get_execution_gas(data_store, 0);
+
+ self.execute_deposit_keeper(key, oracle_params, get_caller_address());
+
+ oracle_modules::with_oracle_prices_after(oracle);
+ // global_reentrancy_guard::non_reentrant_after(data_store);
}
fn simulate_execute_deposit(
ref self: ContractState, key: felt252, params: SimulatePricesParams
- ) { // TODO
+ ) {
+ let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
+ IRoleModule::only_controller(@state);
+
+ let data_store = self.data_store.read();
+ let oracle = self.oracle.read();
+ global_reentrancy_guard::non_reentrant_before(data_store);
+ oracle_modules::with_simulated_oracle_prices_before(oracle, params);
+
+ let oracleParams = Default::default();
+
+ self.execute_deposit_keeper(key, oracleParams, get_caller_address());
+
+ oracle_modules::with_simulated_oracle_prices_after();
+ global_reentrancy_guard::non_reentrant_after(data_store);
}
fn execute_deposit_keeper(
@@ -166,23 +253,49 @@ mod DepositHandler {
key: felt252,
oracle_params: SetPricesParams,
keeper: ContractAddress
- ) { // TODO
- }
- }
+ ) {
+ // let starting_gas = gas_left();
+ let data_store = self.data_store.read();
+ feature_utils::validate_feature(
+ data_store, keys::execute_deposit_feature_disabled_key(get_contract_address())
+ );
+ let min_oracle_block_numbers = oracle_utils::get_uncompacted_oracle_block_numbers(
+ oracle_params.compacted_min_oracle_block_numbers.span(), oracle_params.tokens.len()
+ );
- // *************************************************************************
- // INTERNAL FUNCTIONS
- // *************************************************************************
- #[generate_trait]
- impl InternalImpl of InternalTrait {
- /// Handles error from deposit.
- /// # Arguments
- /// * `key` - The key of the deposit to handle error for.
- /// * `starting_gas` - The starting gas of the transaction.
- /// * `reason_bytes` - The reason of the error.
- fn handle_deposit_error(
- ref self: ContractState, key: felt252, starting_gas: u128, reason_bytes: Array
- ) { // TODO
+ let max_oracle_block_numbers = oracle_utils::get_uncompacted_oracle_block_numbers(
+ oracle_params.compacted_max_oracle_block_numbers.span(), oracle_params.tokens.len()
+ );
+
+ let params = execute_deposit_utils::ExecuteDepositParams {
+ data_store,
+ event_emitter: self.event_emitter.read(),
+ deposit_vault: self.deposit_vault.read(),
+ oracle: self.oracle.read(),
+ key,
+ min_oracle_block_numbers,
+ max_oracle_block_numbers,
+ keeper,
+ starting_gas: 0 // TODO starting_gas
+ };
+
+ execute_deposit_utils::execute_deposit(params);
}
}
+/// TODO no try catch, we need to find alternative
+// // *************************************************************************
+// // INTERNAL FUNCTIONS
+// // *************************************************************************
+// #[generate_trait]
+// impl InternalImpl of InternalTrait {
+// /// Handles error from deposit.
+// /// # Arguments
+// /// * `key` - The key of the deposit to handle error for.
+// /// * `starting_gas` - The starting gas of the transaction.
+// /// * `reason_bytes` - The reason of the error.
+// fn handle_deposit_error(
+// ref self: ContractState, key: felt252, starting_gas: u256, reason_bytes: Array
+// ) { // TODO
+// }
+// }
}
diff --git a/src/exchange/exchange_utils.cairo b/src/exchange/exchange_utils.cairo
index acb42cd5..8ff8f3d4 100644
--- a/src/exchange/exchange_utils.cairo
+++ b/src/exchange/exchange_utils.cairo
@@ -16,7 +16,7 @@ use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
fn validate_request_cancellation(
data_store: IDataStoreDispatcher, created_at_block: u64, request_type: felt252
) {
- let request_expiration_age = data_store.get_u128(keys::request_expiration_block_age());
+ let request_expiration_age = data_store.get_u256(keys::request_expiration_block_age());
let request_age = get_block_number() - created_at_block;
if request_age.into() < request_expiration_age {
diff --git a/src/exchange/liquidation_handler.cairo b/src/exchange/liquidation_handler.cairo
index ed9ff523..68fabc1c 100644
--- a/src/exchange/liquidation_handler.cairo
+++ b/src/exchange/liquidation_handler.cairo
@@ -6,7 +6,7 @@
// Core lib imports.
use core::traits::Into;
-use starknet::ContractAddress;
+use starknet::{ContractAddress, ClassHash};
// Local imports.
use satoru::oracle::oracle_utils::SetPricesParams;
@@ -40,15 +40,14 @@ mod LiquidationHandler {
// *************************************************************************
// Core lib imports.
- use satoru::exchange::base_order_handler::BaseOrderHandler::{
- event_emitter::InternalContractMemberStateTrait, data_store::InternalContractMemberStateImpl
- };
- use starknet::{ContractAddress, get_caller_address, get_contract_address};
+ use starknet::{ContractAddress, get_caller_address, get_contract_address, ClassHash};
// Local imports.
use super::ILiquidationHandler;
use satoru::role::role_store::{IRoleStoreSafeDispatcher, IRoleStoreSafeDispatcherTrait};
+ use satoru::role::role_module::{RoleModule, IRoleModule};
+
use satoru::data::{
data_store::{IDataStoreSafeDispatcher, IDataStoreSafeDispatcherTrait, DataStore},
keys::execute_order_feature_disabled_key
@@ -59,19 +58,28 @@ mod LiquidationHandler {
oracle_utils::SetPricesParams
};
use satoru::order::{
- order_utils, order::{SecondaryOrderType, OrderType, Order},
+ order_utils::{IOrderUtilsDispatcher}, order::{SecondaryOrderType, OrderType, Order},
order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait},
base_order_utils::{ExecuteOrderParams, ExecuteOrderParamsContracts}
};
use satoru::swap::swap_handler::{ISwapHandlerDispatcher, ISwapHandlerDispatcherTrait};
use satoru::market::market::Market;
- use satoru::exchange::base_order_handler::{IBaseOrderHandler, BaseOrderHandler};
+ use satoru::exchange::{
+ order_handler::{IOrderHandler, OrderHandler},
+ base_order_handler::{IBaseOrderHandler, BaseOrderHandler}
+ };
+
+
use satoru::liquidation::liquidation_utils::create_liquidation_order;
- use satoru::exchange::order_handler;
- use debug::PrintTrait;
use satoru::feature::feature_utils::validate_feature;
- use satoru::exchange::order_handler::{IOrderHandler, OrderHandler};
- use satoru::utils::starknet_utils;
+ use satoru::utils::{starknet_utils, global_reentrancy_guard};
+ use satoru::exchange::base_order_handler::BaseOrderHandler::{
+ event_emitter::InternalContractMemberStateTrait,
+ data_store::InternalContractMemberStateImpl,
+ order_utils_lib::InternalContractMemberStateTrait as OrderUtilsTrait,
+ oracle::InternalContractMemberStateTrait as OracleStateTrait,
+ };
+ use satoru::order::order_utils::IOrderUtilsDispatcherTrait;
// *************************************************************************
// STORAGE
@@ -100,7 +108,11 @@ mod LiquidationHandler {
order_vault_address: ContractAddress,
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
- referral_storage_address: ContractAddress
+ referral_storage_address: ContractAddress,
+ order_utils_class_hash: ClassHash,
+ increase_order_utils_class_hash: ClassHash,
+ decrease_order_utils_class_hash: ClassHash,
+ swap_order_utils_class_hash: ClassHash,
) {
let mut state: BaseOrderHandler::ContractState =
BaseOrderHandler::unsafe_new_contract_state();
@@ -112,16 +124,24 @@ mod LiquidationHandler {
order_vault_address,
oracle_address,
swap_handler_address,
- referral_storage_address
+ referral_storage_address,
+ order_utils_class_hash,
+ increase_order_utils_class_hash,
+ decrease_order_utils_class_hash,
+ swap_order_utils_class_hash,
);
+ let mut state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
+ IRoleModule::initialize(ref state, role_store_address,);
}
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
- impl LiquidationHandlerImpl of super::ILiquidationHandler { // executes a position liquidation
+ #[abi(embed_v0)]
+ impl LiquidationHandlerImpl of super::ILiquidationHandler<
+ ContractState
+ > { // executes a position liquidation
fn execute_liquidation(
ref self: ContractState,
account: ContractAddress,
@@ -130,9 +150,23 @@ mod LiquidationHandler {
is_long: bool,
oracle_params: SetPricesParams
) {
- let starting_gas: u128 = starknet_utils::sn_gasleft(array![100]);
- let mut state_base: BaseOrderHandler::ContractState =
+ let mut state_base =
BaseOrderHandler::unsafe_new_contract_state(); //retrieve BaseOrderHandler state
+ global_reentrancy_guard::non_reentrant_before(state_base.data_store.read());
+
+ // let mut role_state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state(); TODO uncomment role
+ // IRoleModule::only_liquidation_keeper(@role_state);
+
+ with_oracle_prices_before(
+ state_base.oracle.read(),
+ state_base.data_store.read(),
+ state_base.event_emitter.read(),
+ @oracle_params
+ );
+
+ // let starting_gas: u128 = starknet_utils::sn_gasleft(array![100]); TODO GAS
+ let starting_gas: u256 = 0;
+
let key: felt252 = create_liquidation_order(
state_base.data_store.read(),
state_base.event_emitter.read(),
@@ -155,7 +189,10 @@ mod LiquidationHandler {
params.contracts.data_store,
execute_order_feature_disabled_key(get_contract_address(), params.order.order_type)
);
- order_utils::execute_order(params);
+ state_base.order_utils_lib.read().execute_order_utils(params);
+ with_oracle_prices_after(state_base.oracle.read());
+
+ global_reentrancy_guard::non_reentrant_after(state_base.data_store.read());
}
}
}
diff --git a/src/exchange/order_handler.cairo b/src/exchange/order_handler.cairo
index b00d250d..da76b138 100644
--- a/src/exchange/order_handler.cairo
+++ b/src/exchange/order_handler.cairo
@@ -5,9 +5,7 @@
// *************************************************************************
// Core lib imports.
-use core::traits::Into;
use starknet::ContractAddress;
-
// Local imports.
use satoru::oracle::oracle_utils::{SetPricesParams, SimulatePricesParams};
use satoru::order::{base_order_utils::CreateOrderParams, order::Order};
@@ -52,15 +50,15 @@ trait IOrderHandler {
/// * `order` - The order to update that will be stored.
/// # Returns
/// The updated order.
- fn update_order(
- ref self: TContractState,
- key: felt252,
- size_delta_usd: u128,
- acceptable_price: u128,
- trigger_price: u128,
- min_output_amount: u128,
- order: Order
- ) -> Order;
+ // fn update_order(
+ // ref self: TContractState,
+ // key: felt252,
+ // size_delta_usd: u256,
+ // acceptable_price: u256,
+ // trigger_price: u256,
+ // min_output_amount: u256,
+ // order: Order
+ // ) -> Order;
/// Cancels the given order. The `cancelOrder()` feature must be enabled for the given order
/// type. The caller must be the owner of the order. The order is cancelled by calling the `cancelOrder()`
@@ -68,7 +66,7 @@ trait IOrderHandler {
/// reason for cancellation, which is passed to the `cancelOrder()` function.
/// # Arguments
/// * `key` - The unique ID of the order to cancel.
- fn cancel_order(ref self: TContractState, key: felt252);
+ // fn cancel_order(ref self: TContractState, key: felt252);
/// Executes an order.
/// # Arguments
@@ -102,29 +100,30 @@ mod OrderHandler {
// *************************************************************************
// Core lib imports.
+ use satoru::exchange::base_order_handler::BaseOrderHandler::order_utils_lib::InternalContractMemberStateTrait;
+ use satoru::order::order_utils::IOrderUtilsDispatcherTrait;
use core::starknet::SyscallResultTrait;
use core::traits::Into;
use starknet::ContractAddress;
- use starknet::{get_caller_address, get_contract_address};
+ use starknet::{get_caller_address, get_contract_address, ClassHash};
use array::ArrayTrait;
+ use debug::PrintTrait;
// Local imports.
use super::IOrderHandler;
- use satoru::oracle::{
- oracle_modules, oracle_utils, oracle_utils::{SetPricesParams, SimulatePricesParams}
- };
- use satoru::order::{base_order_utils::CreateOrderParams, order_utils, order, base_order_utils};
+ use satoru::oracle::oracle_modules;
+
+ use satoru::oracle::oracle_utils::{SetPricesParams, SimulatePricesParams};
use satoru::order::{
+ base_order_utils::CreateOrderParams, order_utils::{IOrderUtilsDispatcher},
order::{Order, OrderTrait, OrderType, SecondaryOrderType},
- order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait}, order_store_utils,
- order_event_utils
+ order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait}
};
- use satoru::market::market::Market;
- use satoru::market::error::MarketError;
- use satoru::position::error::PositionError;
- use satoru::feature::error::FeatureError;
+ // use satoru::market::error::MarketError;
+ // use satoru::position::error::PositionError;
+ // use satoru::feature::error::FeatureError;
use satoru::order::error::OrderError;
- use satoru::exchange::exchange_utils;
+ // use satoru::exchange::exchange_utils;
use satoru::exchange::base_order_handler::{IBaseOrderHandler, BaseOrderHandler};
use satoru::exchange::base_order_handler::BaseOrderHandler::{
role_store::InternalContractMemberStateTrait as RoleStoreStateTrait,
@@ -135,16 +134,19 @@ mod OrderHandler {
oracle::InternalContractMemberStateTrait as OracleStateTrait,
InternalTrait as BaseOrderHandleInternalTrait,
};
- use satoru::feature::feature_utils;
- use satoru::data::keys;
- use satoru::role::role;
+ use satoru::feature::feature_utils::{validate_feature};
+ use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
+ use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
+ use satoru::data::keys::{create_order_feature_disabled_key, execute_order_feature_disabled_key};
+ use satoru::role::role::FROZEN_ORDER_KEEPER;
use satoru::role::role_module::{RoleModule, IRoleModule};
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
- use satoru::token::token_utils;
- use satoru::gas::gas_utils;
- use satoru::chain::chain::Chain;
- use satoru::utils::global_reentrancy_guard;
- use satoru::utils::error_utils;
+ // use satoru::token::token_utils;
+ // use satoru::gas::gas_utils;
+ use satoru::utils::global_reentrancy_guard::{non_reentrant_before, non_reentrant_after};
+ // use satoru::utils::error_utils;
+ use satoru::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
+ use starknet::contract_address_const;
// *************************************************************************
// STORAGE
@@ -173,7 +175,11 @@ mod OrderHandler {
order_vault_address: ContractAddress,
oracle_address: ContractAddress,
swap_handler_address: ContractAddress,
- referral_storage_address: ContractAddress
+ referral_storage_address: ContractAddress,
+ order_utils_class_hash: ClassHash,
+ increase_order_utils_class_hash: ClassHash,
+ decrease_order_utils_class_hash: ClassHash,
+ swap_order_utils_class_hash: ClassHash,
) {
let mut state: BaseOrderHandler::ContractState =
BaseOrderHandler::unsafe_new_contract_state();
@@ -185,7 +191,11 @@ mod OrderHandler {
order_vault_address,
oracle_address,
swap_handler_address,
- referral_storage_address
+ referral_storage_address,
+ order_utils_class_hash,
+ increase_order_utils_class_hash,
+ decrease_order_utils_class_hash,
+ swap_order_utils_class_hash
);
}
@@ -193,169 +203,61 @@ mod OrderHandler {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl OrderHandlerImpl of super::IOrderHandler {
fn create_order(
ref self: ContractState, account: ContractAddress, params: CreateOrderParams
) -> felt252 {
// Check only controller.
- let role_module_state = RoleModule::unsafe_new_contract_state();
- role_module_state.only_controller();
-
+ // let role_module_state = RoleModule::unsafe_new_contract_state(); // TODO uncomment role
+ // role_module_state.only_controller();
// Fetch data store.
let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
let data_store = base_order_handler_state.data_store.read();
- global_reentrancy_guard::non_reentrant_before(data_store);
+ non_reentrant_before(data_store);
// Validate feature and create order.
- feature_utils::validate_feature(
+ validate_feature(
data_store,
- keys::create_order_feature_disabled_key(get_contract_address(), params.order_type)
- );
- let key = order_utils::create_order(
- data_store,
- base_order_handler_state.event_emitter.read(),
- base_order_handler_state.order_vault.read(),
- base_order_handler_state.referral_storage.read(),
- account,
- params
+ create_order_feature_disabled_key(get_contract_address(), params.order_type)
);
+ let key = base_order_handler_state
+ .order_utils_lib
+ .read()
+ .create_order_utils(
+ data_store,
+ base_order_handler_state.event_emitter.read(),
+ base_order_handler_state.order_vault.read(),
+ base_order_handler_state.referral_storage.read(),
+ account,
+ params
+ );
- global_reentrancy_guard::non_reentrant_after(data_store);
+ non_reentrant_after(data_store);
key
}
- fn update_order(
- ref self: ContractState,
- key: felt252,
- size_delta_usd: u128,
- acceptable_price: u128,
- trigger_price: u128,
- min_output_amount: u128,
- order: Order
- ) -> Order {
- // Check only controller.
- let role_module_state = RoleModule::unsafe_new_contract_state();
- role_module_state.only_controller();
-
- // Fetch data store.
- let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
- let data_store = base_order_handler_state.data_store.read();
-
- global_reentrancy_guard::non_reentrant_before(data_store);
-
- // Validate feature.
- feature_utils::validate_feature(
- data_store,
- keys::update_order_feature_disabled_key(get_contract_address(), order.order_type)
- );
-
- assert(base_order_utils::is_market_order(order.order_type), 'OrderNotUpdatable');
-
- let mut updated_order = order.clone();
- updated_order.size_delta_usd = size_delta_usd;
- updated_order.trigger_price = trigger_price;
- updated_order.acceptable_price = acceptable_price;
- updated_order.min_output_amount = min_output_amount;
- updated_order.is_frozen = false;
-
- // Allow topping up of execution fee as frozen orders will have execution fee reduced.
- let fee_token = token_utils::fee_token(data_store);
- let order_vault = base_order_handler_state.order_vault.read();
- let received_fee_token = order_vault.record_transfer_in(fee_token);
- updated_order.execution_fee = received_fee_token;
-
- let estimated_gas_limit = gas_utils::estimate_execute_order_gas_limit(
- data_store, @updated_order
- );
- gas_utils::validate_execution_fee(
- data_store, estimated_gas_limit, updated_order.execution_fee
- );
-
- updated_order.touch();
-
- base_order_utils::validate_non_empty_order(@updated_order);
-
- order_store_utils::set(data_store, key, @updated_order);
- order_event_utils::emit_order_updated(
- base_order_handler_state.event_emitter.read(),
- key,
- size_delta_usd,
- acceptable_price,
- trigger_price,
- min_output_amount,
- );
-
- global_reentrancy_guard::non_reentrant_after(data_store);
-
- updated_order
- }
-
- fn cancel_order(ref self: ContractState, key: felt252) {
- let starting_gas: u128 = 0; // TODO: Get starting gas from Cairo.
-
- // Check only controller.
- let role_module_state = RoleModule::unsafe_new_contract_state();
- role_module_state.only_controller();
-
- // Fetch data store.
- let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
- let data_store = base_order_handler_state.data_store.read();
-
- global_reentrancy_guard::non_reentrant_before(data_store);
-
- let order = order_store_utils::get(data_store, key);
-
- // Validate feature.
- feature_utils::validate_feature(
- data_store,
- keys::cancel_order_feature_disabled_key(get_contract_address(), order.order_type)
- );
-
- if base_order_utils::is_market_order(order.order_type) {
- exchange_utils::validate_request_cancellation(
- data_store, order.updated_at_block, 'Order'
- )
- }
-
- order_utils::cancel_order(
- data_store,
- base_order_handler_state.event_emitter.read(),
- base_order_handler_state.order_vault.read(),
- key,
- order.account,
- starting_gas,
- keys::user_initiated_cancel(),
- ArrayTrait::::new(),
- );
-
- global_reentrancy_guard::non_reentrant_after(data_store);
- }
fn execute_order(ref self: ContractState, key: felt252, oracle_params: SetPricesParams) {
// Check only order keeper.
let role_module_state = RoleModule::unsafe_new_contract_state();
role_module_state.only_order_keeper();
-
// Fetch data store.
let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
let data_store = base_order_handler_state.data_store.read();
-
- global_reentrancy_guard::non_reentrant_before(data_store);
+ // non_reentrant_before(data_store);
oracle_modules::with_oracle_prices_before(
base_order_handler_state.oracle.read(),
data_store,
base_order_handler_state.event_emitter.read(),
@oracle_params
);
-
// TODO: Did not implement starting gas and try / catch logic as not available in Cairo
self._execute_order(key, oracle_params, get_contract_address());
-
oracle_modules::with_oracle_prices_after(base_order_handler_state.oracle.read());
- global_reentrancy_guard::non_reentrant_after(data_store);
+ // non_reentrant_after(data_store);
}
fn execute_order_keeper(
@@ -378,16 +280,16 @@ mod OrderHandler {
let base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
let data_store = base_order_handler_state.data_store.read();
- global_reentrancy_guard::non_reentrant_before(data_store);
- oracle_modules::with_simulated_oracle_prices_before(
- base_order_handler_state.oracle.read(), params
- );
+ non_reentrant_before(data_store);
+ // oracle_modules::with_simulated_oracle_prices_before(
+ // base_order_handler_state.oracle.read(), params
+ // );
let oracle_params: SetPricesParams = Default::default();
self._execute_order(key, oracle_params, get_contract_address());
- oracle_modules::with_simulated_oracle_prices_after();
- global_reentrancy_guard::non_reentrant_after(data_store);
+ // oracle_modules::with_simulated_oracle_prices_after();
+ non_reentrant_after(data_store);
}
}
@@ -407,7 +309,7 @@ mod OrderHandler {
oracle_params: SetPricesParams,
keeper: ContractAddress
) {
- let starting_gas: u128 = 0; // TODO: Get starting gas from Cairo.
+ let starting_gas: u256 = 100000; // TODO: Get starting gas from Cairo.
// Check only self.
let role_module_state = RoleModule::unsafe_new_contract_state();
@@ -424,73 +326,14 @@ mod OrderHandler {
}
// Validate feature.
- feature_utils::validate_feature(
+ validate_feature(
params.contracts.data_store,
- keys::execute_order_feature_disabled_key(
- get_contract_address(), params.order.order_type
- )
+ execute_order_feature_disabled_key(get_contract_address(), params.order.order_type)
);
- order_utils::execute_order(params);
+ base_order_handler_state.order_utils_lib.read().execute_order_utils(params);
}
- /// Handles error from order.
- /// # Arguments
- /// * `key` - The key of the deposit to handle error for.
- /// * `starting_gas` - The starting gas of the transaction.
- /// * `reason` - The reason of the error.
- fn handle_order_error(
- self: @ContractState, key: felt252, starting_gas: u128, reason_bytes: Array
- ) {
- let error_selector = error_utils::get_error_selector_from_data(reason_bytes.span());
-
- let mut base_order_handler_state = BaseOrderHandler::unsafe_new_contract_state();
- let data_store = base_order_handler_state.data_store.read();
-
- let order = order_store_utils::get(data_store, key);
- let is_market_order = base_order_utils::is_market_order(order.order_type);
-
- if (oracle_utils::is_oracle_error(error_selector)
- || order.is_frozen
- || (!is_market_order && error_selector == PositionError::EMPTY_POSITION)
- || error_selector == OrderError::EMPTY_ORDER
- || error_selector == FeatureError::DISABLED_FEATURE
- || error_selector == OrderError::INVALID_KEEPER_FOR_FROZEN_ORDER
- || error_selector == OrderError::UNSUPPORTED_ORDER_TYPE
- || error_selector == OrderError::INVALID_ORDER_PRICES) {
- assert(false, error_utils::revert_with_custom_error(reason_bytes.span()))
- }
-
- let reason = error_utils::get_revert_message(reason_bytes.span());
-
- if (is_market_order
- || error_selector == MarketError::INVALID_POSITION_MARKET
- || error_selector == MarketError::INVALID_COLLATERAL_TOKEN_FOR_MARKET
- || error_selector == PositionError::INVALID_POSITION_SIZE_VALUES) {
- order_utils::cancel_order(
- data_store,
- base_order_handler_state.event_emitter.read(),
- base_order_handler_state.order_vault.read(),
- key,
- order.account,
- starting_gas,
- reason,
- reason_bytes,
- );
- return ();
- }
-
- order_utils::freeze_order(
- data_store,
- base_order_handler_state.event_emitter.read(),
- base_order_handler_state.order_vault.read(),
- key,
- get_caller_address(),
- starting_gas,
- reason,
- reason_bytes
- );
- }
/// Validate that the keeper is a frozen order keeper.
/// # Arguments
@@ -500,7 +343,7 @@ mod OrderHandler {
let role_store = base_order_handler_state.role_store.read();
assert(
- role_store.has_role(keeper, role::FROZEN_ORDER_KEEPER),
+ role_store.has_role(keeper, FROZEN_ORDER_KEEPER),
OrderError::INVALID_FROZEN_ORDER_KEEPER
);
}
diff --git a/src/exchange/withdrawal_handler.cairo b/src/exchange/withdrawal_handler.cairo
index c5fbc24e..dac9aaba 100644
--- a/src/exchange/withdrawal_handler.cairo
+++ b/src/exchange/withdrawal_handler.cairo
@@ -57,7 +57,6 @@ mod WithdrawalHandler {
use starknet::{ContractAddress, get_contract_address, get_caller_address};
use traits::Default;
use clone::Clone;
-
// Local imports.
use super::IWithdrawalHandler;
use satoru::role::{role, role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait}};
@@ -136,7 +135,7 @@ mod WithdrawalHandler {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl WithdrawalHandlerImpl of super::IWithdrawalHandler {
fn create_withdrawal(
ref self: ContractState, account: ContractAddress, params: CreateWithdrawalParams
@@ -175,8 +174,8 @@ mod WithdrawalHandler {
global_reentrancy_guard::non_reentrant_before(data_store); // Initiates re-entrancy
- let starting_gas = starknet_utils::sn_gasleft(array![100]); // Returns 100 for now,
- let withdrawal = data_store.get_withdrawal(key).unwrap(); // Panics if Option::None
+ let starting_gas = starknet_utils::sn_gasleft(array![200]); // Returns 200 for now,
+ let withdrawal = data_store.get_withdrawal(key);
feature_utils::validate_feature(
data_store, keys::cancel_withdrawal_feature_disabled_key(get_contract_address())
@@ -231,19 +230,19 @@ mod WithdrawalHandler {
price_feed_tokens: oracle_params.price_feed_tokens.clone(),
};
// withOraclePrices
- oracle_modules::with_oracle_prices_before(
- self.oracle.read(),
- self.data_store.read(),
- self.event_emitter.read(),
- @oracle_params
- );
+ // oracle_modules::with_oracle_prices_before(
+ // self.oracle.read(),
+ // self.data_store.read(),
+ // self.event_emitter.read(),
+ // @oracle_params
+ // );
let starting_gas = starknet_utils::sn_gasleft(array![100]);
let execution_gas = gas_utils::get_execution_gas(data_store, starting_gas);
self.execute_withdrawal_keeper(key, oracle_params_copy, get_caller_address());
- oracle_modules::with_oracle_prices_after(self.oracle.read());
+ // oracle_modules::with_oracle_prices_after(self.oracle.read());
global_reentrancy_guard::non_reentrant_after(data_store); // Finalizes re-entrancy
}
@@ -297,7 +296,7 @@ mod WithdrawalHandler {
/// * `starting_gas` - The starting gas of the transaction.
/// * `reason_bytes` - The reason of the error.
fn handle_withdrawal_error(
- ref self: ContractState, key: felt252, starting_gas: u128, reason_bytes: Array
+ ref self: ContractState, key: felt252, starting_gas: u256, reason_bytes: Array
) {
// Just cancels withdrawal. There is no way to handle revert and revert reason right now.
diff --git a/src/feature/feature_utils.cairo b/src/feature/feature_utils.cairo
index f7b52440..c2a1e84f 100644
--- a/src/feature/feature_utils.cairo
+++ b/src/feature/feature_utils.cairo
@@ -16,10 +16,7 @@ use satoru::feature::error::FeatureError;
/// # Returns
/// whether the feature is disabled.
fn is_feature_disabled(data_store: IDataStoreDispatcher, key: felt252) -> bool {
- match data_store.get_bool(key) {
- Option::Some(value) => value,
- Option::None => false
- }
+ data_store.get_bool(key)
}
/// Validate whether a feature is enabled, reverts if the feature is disabled.
diff --git a/src/fee/fee_handler.cairo b/src/fee/fee_handler.cairo
index eeda6679..ea7f8e76 100644
--- a/src/fee/fee_handler.cairo
+++ b/src/fee/fee_handler.cairo
@@ -44,7 +44,6 @@ mod FeeHandler {
use core::zeroable::Zeroable;
use starknet::{get_caller_address, ContractAddress, contract_address_const};
- use debug::PrintTrait;
// Local imports.
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
@@ -92,7 +91,7 @@ mod FeeHandler {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl FeeHandlerImpl of super::IFeeHandler {
fn initialize(
ref self: ContractState,
diff --git a/src/fee/fee_utils.cairo b/src/fee/fee_utils.cairo
index 668c2b66..a196bdb0 100644
--- a/src/fee/fee_utils.cairo
+++ b/src/fee/fee_utils.cairo
@@ -5,11 +5,11 @@
use starknet::ContractAddress;
// Local imports.
+use satoru::bank::bank::{IBankDispatcher, IBankDispatcherTrait};
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
-use satoru::data::keys::{
- claim_fee_amount_key, claim_ui_fee_amount_key, claim_ui_fee_amount_for_account_key
-};
+use satoru::market::{market, market_utils::validate_market_token_balance_with_address};
+use satoru::data::keys;
use satoru::utils::account_utils::validate_receiver;
/// Increment the claimable fee amount for the specified market.
@@ -25,16 +25,16 @@ fn increment_claimable_fee_amount(
event_emitter: IEventEmitterDispatcher,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
+ delta: u256,
fee_type: felt252,
) {
if delta == 0 {
return;
}
- let key = claim_fee_amount_key(market, token);
+ let key = keys::claimable_fee_amount_key(market, token);
- let next_value = data_store.increment_u128(key, delta);
+ let next_value = data_store.increment_u256(key, delta);
event_emitter.emit_claimable_fee_amount_updated(market, token, delta, next_value, fee_type);
}
@@ -54,7 +54,7 @@ fn increment_claimable_ui_fee_amount(
ui_fee_receiver: ContractAddress,
market: ContractAddress,
token: ContractAddress,
- delta: u128,
+ delta: u256,
fee_type: felt252,
) {
if delta == 0 {
@@ -62,10 +62,12 @@ fn increment_claimable_ui_fee_amount(
}
let next_value = data_store
- .increment_u128(claim_ui_fee_amount_for_account_key(market, token, ui_fee_receiver), delta);
-
- let next_pool_value = data_store.increment_u128(claim_ui_fee_amount_key(market, token), delta);
+ .increment_u256(
+ keys::claimable_ui_fee_amount_for_account_key(market, token, ui_fee_receiver), delta
+ );
+ let next_pool_value = data_store
+ .increment_u256(keys::claimable_ui_fee_amount_key(market, token), delta);
event_emitter
.emit_claimable_ui_fee_amount_updated(
ui_fee_receiver, market, token, delta, next_value, next_pool_value, fee_type
@@ -85,7 +87,19 @@ fn claim_fees(
market: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
-) { // TODO
+) {
+ validate_receiver(receiver);
+
+ let key = keys::claimable_fee_amount_key(market, token);
+
+ let fee_amount = data_store.get_u256(key);
+ data_store.set_u256(key, 0);
+
+ IBankDispatcher { contract_address: market }.transfer_out(market, token, receiver, fee_amount);
+
+ validate_market_token_balance_with_address(data_store, market);
+
+ event_emitter.emit_fees_claimed(market, receiver, fee_amount);
}
/// Claim ui fees for the specified market.
@@ -103,7 +117,22 @@ fn claim_ui_fees(
market: ContractAddress,
token: ContractAddress,
receiver: ContractAddress,
-) -> u128 {
- // TODO
- 0
+) -> u256 {
+ validate_receiver(receiver);
+
+ let key = keys::claimable_ui_fee_amount_for_account_key(market, token, ui_fee_receiver);
+ let fee_amount = data_store.get_u256(key);
+ data_store.set_u256(key, 0);
+
+ let next_pool_value = data_store
+ .decrement_u256(keys::claimable_ui_fee_amount_key(market, token), fee_amount);
+
+ IBankDispatcher { contract_address: market }.transfer_out(market, token, receiver, fee_amount);
+
+ validate_market_token_balance_with_address(data_store, market);
+
+ event_emitter
+ .emit_ui_fees_claimed(ui_fee_receiver, market, receiver, fee_amount, next_pool_value);
+
+ fee_amount
}
diff --git a/src/gas/gas_utils.cairo b/src/gas/gas_utils.cairo
index ddfaf1d5..fba55c3f 100644
--- a/src/gas/gas_utils.cairo
+++ b/src/gas/gas_utils.cairo
@@ -8,8 +8,10 @@ use starknet::ContractAddress;
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::data::keys;
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
+use satoru::bank::bank::{IBankDispatcher, IBankDispatcherTrait};
use satoru::bank::strict_bank::{IStrictBankDispatcher, IStrictBankDispatcherTrait};
use satoru::order::{
+ order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait},
order::{Order, DecreasePositionSwapType},
base_order_utils::{is_increase_order, is_decrease_order, is_swap_order, OrderError}
};
@@ -29,13 +31,13 @@ use satoru::gas::error::GasError;
/// * `data_store` - The data storage dispatcher.
/// # Returns
/// The MIN_HANDLE_EXECUTION_ERROR_GAS.
-fn get_min_handle_execution_error_gas(data_store: IDataStoreDispatcher) -> u128 {
- data_store.get_u128(keys::min_handle_execution_error_gas())
+fn get_min_handle_execution_error_gas(data_store: IDataStoreDispatcher) -> u256 {
+ data_store.get_u256(keys::min_handle_execution_error_gas())
}
/// Check that starting gas is higher than min handle execution gas and return starting.
/// gas minus min_handle_error_gas.
-fn get_execution_gas(data_store: IDataStoreDispatcher, starting_gas: u128) -> u128 {
+fn get_execution_gas(data_store: IDataStoreDispatcher, starting_gas: u256) -> u256 {
let min_handle_error_gas = get_min_handle_execution_error_gas(data_store);
if starting_gas < min_handle_error_gas {
panic(array![GasError::INSUFF_EXEC_GAS]);
@@ -57,9 +59,9 @@ fn get_execution_gas(data_store: IDataStoreDispatcher, starting_gas: u128) -> u1
fn pay_execution_fee(
data_store: IDataStoreDispatcher,
event_emitter: IEventEmitterDispatcher,
- bank: IWithdrawalVaultDispatcher,
- execution_fee: u128,
- starting_gas: u128,
+ bank: IBankDispatcher,
+ execution_fee: u256,
+ starting_gas: u256,
keeper: ContractAddress,
refund_receiver: ContractAddress
) {
@@ -77,7 +79,7 @@ fn pay_execution_fee(
execution_fee_for_keeper = execution_fee;
}
- bank.transfer_out(fee_token, keeper, execution_fee_for_keeper);
+ bank.transfer_out(bank.contract_address, fee_token, keeper, execution_fee_for_keeper);
event_emitter.emit_keeper_execution_fee(keeper, execution_fee_for_keeper);
@@ -88,7 +90,7 @@ fn pay_execution_fee(
return;
}
- bank.transfer_out(fee_token, refund_receiver, refund_fee_amount);
+ bank.transfer_out(bank.contract_address, fee_token, refund_receiver, refund_fee_amount);
event_emitter.emit_execution_fee_refund(refund_receiver, refund_fee_amount);
}
@@ -97,8 +99,87 @@ fn pay_execution_fee_deposit(
data_store: IDataStoreDispatcher,
event_emitter: IEventEmitterDispatcher,
bank: IDepositVaultDispatcher,
- execution_fee: u128,
- starting_gas: u128,
+ execution_fee: u256,
+ starting_gas: u256,
+ keeper: ContractAddress,
+ refund_receiver: ContractAddress
+) {
+ let fee_token: ContractAddress = token_utils::fee_token(data_store);
+
+ // 63/64 gas is forwarded to external calls, reduce the startingGas to account for this
+ // let reduced_starting_gas = starting_gas - sn_gasleft(array![100]) / 63;
+ // let gas_used = reduced_starting_gas - sn_gasleft(array![100]);
+
+ let gas_used = 0;
+ // each external call forwards 63/64 of the remaining gas
+ let mut execution_fee_for_keeper = adjust_gas_usage(data_store, gas_used)
+ * sn_gasprice(array![10]);
+
+ if (execution_fee_for_keeper > execution_fee) {
+ execution_fee_for_keeper = execution_fee;
+ }
+
+ bank.transfer_out(bank.contract_address, fee_token, keeper, execution_fee_for_keeper);
+
+ event_emitter.emit_keeper_execution_fee(keeper, execution_fee_for_keeper);
+
+ let refund_fee_amount = execution_fee - execution_fee_for_keeper;
+
+ let refund_fee_amount = execution_fee - execution_fee_for_keeper;
+ if (refund_fee_amount == 0) {
+ return;
+ }
+
+ bank.transfer_out(bank.contract_address, fee_token, refund_receiver, refund_fee_amount);
+
+ event_emitter.emit_execution_fee_refund(refund_receiver, refund_fee_amount);
+}
+
+fn pay_execution_fee_order(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ bank: IOrderVaultDispatcher,
+ execution_fee: u256,
+ starting_gas: u256,
+ keeper: ContractAddress,
+ refund_receiver: ContractAddress
+) {
+ let fee_token: ContractAddress = token_utils::fee_token(data_store);
+
+ // 63/64 gas is forwarded to external calls, reduce the startingGas to account for this
+ let reduced_starting_gas = starting_gas - sn_gasleft(array![100]) / 63;
+ let gas_used = reduced_starting_gas - sn_gasleft(array![0]);
+
+ // each external call forwards 63/64 of the remaining gas
+ let mut execution_fee_for_keeper = adjust_gas_usage(data_store, gas_used)
+ * sn_gasprice(array![10]);
+
+ if (execution_fee_for_keeper > execution_fee) {
+ execution_fee_for_keeper = execution_fee;
+ }
+
+ bank.transfer_out(bank.contract_address, fee_token, keeper, execution_fee_for_keeper);
+
+ event_emitter.emit_keeper_execution_fee(keeper, execution_fee_for_keeper);
+
+ let refund_fee_amount = execution_fee - execution_fee_for_keeper;
+
+ let refund_fee_amount = execution_fee - execution_fee_for_keeper;
+ if (refund_fee_amount == 0) {
+ return;
+ }
+
+ bank.transfer_out(bank.contract_address, fee_token, refund_receiver, refund_fee_amount);
+
+ event_emitter.emit_execution_fee_refund(refund_receiver, refund_fee_amount);
+}
+
+fn pay_execution_fee_withdrawal(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ bank: IWithdrawalVaultDispatcher,
+ execution_fee: u256,
+ starting_gas: u256,
keeper: ContractAddress,
refund_receiver: ContractAddress
) {
@@ -116,7 +197,7 @@ fn pay_execution_fee_deposit(
execution_fee_for_keeper = execution_fee;
}
- bank.transfer_out(fee_token, keeper, execution_fee_for_keeper);
+ bank.transfer_out(bank.contract_address, fee_token, keeper, execution_fee_for_keeper);
event_emitter.emit_keeper_execution_fee(keeper, execution_fee_for_keeper);
@@ -127,7 +208,7 @@ fn pay_execution_fee_deposit(
return;
}
- bank.transfer_out(fee_token, refund_receiver, refund_fee_amount);
+ bank.transfer_out(bank.contract_address, fee_token, refund_receiver, refund_fee_amount);
event_emitter.emit_execution_fee_refund(refund_receiver, refund_fee_amount);
}
@@ -140,7 +221,7 @@ fn pay_execution_fee_deposit(
/// # Returns
/// * The key for the account order list.
fn validate_execution_fee(
- data_store: IDataStoreDispatcher, estimated_gas_limit: u128, execution_fee: u128
+ data_store: IDataStoreDispatcher, estimated_gas_limit: u256, execution_fee: u256
) {
let gas_limit = adjust_gas_limit_for_estimate(data_store, estimated_gas_limit);
let min_execution_fee = gas_limit * sn_gasprice(array![10]);
@@ -153,7 +234,7 @@ fn validate_execution_fee(
/// # Arguments
/// * `data_store` - The data storage contract dispatcher.
/// * `gas_used` - The amount of gas used.
-fn adjust_gas_usage(data_store: IDataStoreDispatcher, gas_used: u128) -> u128 {
+fn adjust_gas_usage(data_store: IDataStoreDispatcher, gas_used: u256) -> u256 {
// gas measurements are done after the call to with_oracle_prices
// with_oracle_prices may consume a significant amount of gas
// the base_gas_limit used to calculate the execution cost
@@ -161,12 +242,12 @@ fn adjust_gas_usage(data_store: IDataStoreDispatcher, gas_used: u128) -> u128 {
// additionally, a transaction could fail midway through an execution transaction
// before being cancelled, the possibility of this additional gas cost should
// be considered when setting the base_gas_limit
- let base_gas_limit = data_store.get_u128(keys::execution_gas_fee_base_amount());
+ let base_gas_limit = data_store.get_u256(keys::execution_gas_fee_base_amount());
// the gas cost is estimated based on the gasprice of the request txn
// the actual cost may be higher if the gasprice is higher in the execution txn
// the multiplier_factor should be adjusted to account for this
- let multiplier_factor = data_store.get_u128(keys::execution_gas_fee_multiplier_factor());
- base_gas_limit + precision::apply_factor_u128(gas_used, multiplier_factor)
+ let multiplier_factor = data_store.get_u256(keys::execution_gas_fee_multiplier_factor());
+ base_gas_limit + precision::apply_factor_u256(gas_used, multiplier_factor)
}
/// Adjust the estimated gas limit to help ensure the execution fee is sufficient during the actual execution.
@@ -176,29 +257,29 @@ fn adjust_gas_usage(data_store: IDataStoreDispatcher, gas_used: u128) -> u128 {
/// # Returns
/// The adjusted gas limit
fn adjust_gas_limit_for_estimate(
- data_store: IDataStoreDispatcher, estimated_gas_limit: u128
-) -> u128 {
- let base_gas_limit = data_store.get_u128(keys::estimated_gas_fee_base_amount());
- let multiplier_factor = data_store.get_u128(keys::estimated_gas_fee_multiplier_factor());
- base_gas_limit + precision::apply_factor_u128(estimated_gas_limit, multiplier_factor)
+ data_store: IDataStoreDispatcher, estimated_gas_limit: u256
+) -> u256 {
+ let base_gas_limit = data_store.get_u256(keys::estimated_gas_fee_base_amount());
+ let multiplier_factor = data_store.get_u256(keys::estimated_gas_fee_multiplier_factor());
+ base_gas_limit + precision::apply_factor_u256(estimated_gas_limit, multiplier_factor)
}
/// The estimated gas limit for deposits.
/// # Arguments
/// * `data_store` - The data storage contract dispatcher.
/// * `deposit` - The deposit to estimate the gas limit for.
-fn estimate_execute_deposit_gas_limit(data_store: IDataStoreDispatcher, deposit: Deposit) -> u128 {
- let gas_per_swap = data_store.get_u128(keys::single_swap_gas_limit());
+fn estimate_execute_deposit_gas_limit(data_store: IDataStoreDispatcher, deposit: Deposit) -> u256 {
+ let gas_per_swap = data_store.get_u256(keys::single_swap_gas_limit());
let swap_count = deposit.long_token_swap_path.len() + deposit.short_token_swap_path.len();
let gas_for_swaps = swap_count.into() * gas_per_swap;
if (deposit.initial_long_token_amount == 0 || deposit.initial_short_token_amount == 0) {
- return data_store.get_u128(keys::deposit_gas_limit_key(true))
+ return data_store.get_u256(keys::deposit_gas_limit_key(true))
+ deposit.callback_gas_limit
+ gas_for_swaps;
}
- return data_store.get_u128(keys::deposit_gas_limit_key(false))
+ return data_store.get_u256(keys::deposit_gas_limit_key(false))
+ deposit.callback_gas_limit
+ gas_for_swaps;
}
@@ -209,11 +290,11 @@ fn estimate_execute_deposit_gas_limit(data_store: IDataStoreDispatcher, deposit:
/// * `withdrawal` - The withdrawal to estimate the gas limit for.
fn estimate_execute_withdrawal_gas_limit(
data_store: IDataStoreDispatcher, withdrawal: Withdrawal
-) -> u128 {
- let gas_per_swap = data_store.get_u128(keys::single_swap_gas_limit());
+) -> u256 {
+ let gas_per_swap = data_store.get_u256(keys::single_swap_gas_limit());
let swap_count = withdrawal.long_token_swap_path.len() + withdrawal.short_token_swap_path.len();
let gas_for_swaps = swap_count.into() * gas_per_swap;
- return data_store.get_u128(keys::withdrawal_gas_limit_key())
+ return data_store.get_u256(keys::withdrawal_gas_limit_key())
+ withdrawal.callback_gas_limit
+ gas_for_swaps;
}
@@ -222,7 +303,7 @@ fn estimate_execute_withdrawal_gas_limit(
/// # Arguments
/// * `data_store` - The data storage contract dispatcher.
/// * `order` - The order to estimate the gas limit for.
-fn estimate_execute_order_gas_limit(data_store: IDataStoreDispatcher, order: @Order) -> u128 {
+fn estimate_execute_order_gas_limit(data_store: IDataStoreDispatcher, order: @Order) -> u256 {
if (is_increase_order(*order.order_type)) {
return estimate_execute_increase_order_gas_limit(data_store, *order);
}
@@ -245,9 +326,9 @@ fn estimate_execute_order_gas_limit(data_store: IDataStoreDispatcher, order: @Or
/// * `order` - The order to estimate the gas limit for.
fn estimate_execute_increase_order_gas_limit(
data_store: IDataStoreDispatcher, order: Order
-) -> u128 {
- let gas_per_swap = data_store.get_u128(keys::single_swap_gas_limit_key());
- return data_store.get_u128(keys::increase_order_gas_limit_key())
+) -> u256 {
+ let gas_per_swap = data_store.get_u256(keys::single_swap_gas_limit_key());
+ return data_store.get_u256(keys::increase_order_gas_limit_key())
+ gas_per_swap * order.swap_path.len().into()
+ order.callback_gas_limit;
}
@@ -258,12 +339,12 @@ fn estimate_execute_increase_order_gas_limit(
/// * `order` - The order to estimate the gas limit for.
fn estimate_execute_decrease_order_gas_limit(
data_store: IDataStoreDispatcher, order: Order
-) -> u128 {
- let mut gas_per_swap = data_store.get_u128(keys::single_swap_gas_limit_key());
+) -> u256 {
+ let mut gas_per_swap = data_store.get_u256(keys::single_swap_gas_limit_key());
if (order.decrease_position_swap_type != DecreasePositionSwapType::NoSwap) {
gas_per_swap += 1;
}
- return data_store.get_u128(keys::decrease_order_gas_limit_key())
+ return data_store.get_u256(keys::decrease_order_gas_limit_key())
+ gas_per_swap * order.swap_path.len().into()
+ order.callback_gas_limit;
}
@@ -272,9 +353,9 @@ fn estimate_execute_decrease_order_gas_limit(
/// # Arguments
/// * `data_store` - The data storage contract dispatcher.
/// * `order` - The order to estimate the gas limit for.
-fn estimate_execute_swap_order_gas_limit(data_store: IDataStoreDispatcher, order: Order) -> u128 {
- let gas_per_swap = data_store.get_u128(keys::single_swap_gas_limit_key());
- return data_store.get_u128(keys::swap_order_gas_limit_key())
+fn estimate_execute_swap_order_gas_limit(data_store: IDataStoreDispatcher, order: Order) -> u256 {
+ let gas_per_swap = data_store.get_u256(keys::single_swap_gas_limit_key());
+ return data_store.get_u256(keys::swap_order_gas_limit_key())
+ gas_per_swap * order.swap_path.len().into()
+ order.callback_gas_limit;
}
diff --git a/src/lib.cairo b/src/lib.cairo
index 7fdf19d3..aa1fb618 100644
--- a/src/lib.cairo
+++ b/src/lib.cairo
@@ -65,7 +65,7 @@ mod deposit {
// `exchange` contains main satoru handlers to create and execute actions.
mod exchange {
- mod adl_handler;
+ // mod adl_handler;
mod base_order_handler;
mod deposit_handler;
mod error;
@@ -144,13 +144,17 @@ mod utils {
mod global_reentrancy_guard;
mod precision;
mod span32;
- mod u128_mask;
+ mod u256_mask;
mod hash;
- mod i128;
+ mod i256;
+ mod i256_test_storage_contract;
mod store_arrays;
mod error_utils;
mod starknet_utils;
mod traits;
+ mod default;
+ mod serializable_dict;
+ mod felt_math;
}
// `liquidation` function to help with liquidations.
@@ -160,19 +164,20 @@ mod liquidation {
// `market` contains market management functions.
mod market {
- mod market_utils;
mod error;
- mod market_token;
- mod market_factory;
mod market;
+ mod market_factory;
mod market_pool_value_info;
- mod market_event_utils;
+ mod market_store_utils;
+ mod market_token;
+ mod market_utils;
}
mod mock {
mod error;
mod governable;
mod referral_storage;
+ mod mock_account;
}
// `oracle` contains functions related to oracles used by Satoru.
@@ -183,6 +188,9 @@ mod oracle {
mod oracle_utils;
mod oracle;
mod price_feed;
+ mod interfaces {
+ mod account;
+ }
}
// `order` contains order management functions.
@@ -193,9 +201,8 @@ mod order {
mod increase_order_utils;
mod order_vault;
mod order;
- mod order_store_utils;
- mod order_event_utils;
mod error;
+ mod swap_order_utils;
}
// `position` contains positions management functions
@@ -212,6 +219,7 @@ mod position {
// `pricing` contains pricing utils
mod pricing {
+ mod error;
mod position_pricing_utils;
mod pricing_utils;
mod swap_pricing_utils;
@@ -236,118 +244,11 @@ mod token {
mod token_utils;
}
-// This is a temporary solution for tests until they resolve the issue (https://github.com/foundry-rs/starknet-foundry/issues/647)
-mod tests {
- mod adl {
- mod test_adl_utils;
- }
- mod bank {
- mod test_bank;
- }
- mod callback {
- mod test_callback_utils;
- }
- mod config {
- mod test_config;
- }
- mod data {
- mod test_data_store;
- mod test_deposit_store;
- mod test_keys;
- mod test_market;
- mod test_order;
- mod test_position;
- mod test_withdrawal;
- }
- mod deposit {
- mod test_deposit_utils;
- mod test_deposit_vault;
- mod test_execute_deposit_utils;
- }
- mod event {
- mod test_adl_events_emitted;
- mod test_callback_events_emitted;
- mod test_config_events_emitted;
- mod test_gas_events_emitted;
- mod test_market_events_emitted;
- mod test_oracle_events_emitted;
- mod test_order_events_emitted;
- mod test_position_events_emitted;
- mod test_pricing_events_emitted;
- mod test_referral_events_emitted;
- mod test_swap_events_emitted;
- mod test_timelock_events_emitted;
- mod test_withdrawal_events_emitted;
- }
- mod exchange {
- mod test_liquidation_handler;
- mod test_withdrawal_handler;
- }
- mod feature {
- mod test_feature_utils;
- }
- mod fee {
- mod test_fee_handler;
- mod test_fee_utils;
- }
- mod market {
- mod test_market_factory;
- mod test_market_token;
- mod test_market_utils;
- }
- mod nonce {
- mod test_nonce_utils;
- }
- mod oracle {
- mod test_oracle;
- }
- mod order {
- mod test_base_order_utils;
- mod test_order;
- }
- mod position {
- mod test_decrease_position_swap_utils;
- mod test_position_utils;
- }
- mod price {
- mod test_price;
- }
-
- mod reader {
- mod test_reader;
- }
-
- mod role {
- mod test_role_module;
- mod test_role_store;
- }
- mod router {
- mod test_router;
- }
- mod swap {
- mod test_swap_handler;
- }
- mod utils {
- mod test_account_utils;
- mod test_arrays;
- mod test_basic_multicall;
- mod test_calc;
- mod test_enumerable_set;
- mod test_precision;
- mod test_reentrancy_guard;
- mod test_starknet_utils;
- mod test_u128_mask;
- mod test_i128;
- }
- mod mock {
- mod test_referral_utils;
- mod test_governable;
- mod test_referral_storage;
- }
+mod test_utils {
+ mod deposit_setup;
+ mod tests_lib;
}
-mod tests_lib;
-
// `withdrawal` contains withdrawal management functions
mod withdrawal {
mod error;
diff --git a/src/liquidation/liquidation_utils.cairo b/src/liquidation/liquidation_utils.cairo
index d2c65d96..c7d60bfc 100644
--- a/src/liquidation/liquidation_utils.cairo
+++ b/src/liquidation/liquidation_utils.cairo
@@ -6,7 +6,14 @@ use starknet::ContractAddress;
// Local imports.
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
+use satoru::data::keys;
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
+use satoru::position::position_utils::get_position_key;
+use satoru::order::order::{SecondaryOrderType, OrderType, Order, DecreasePositionSwapType};
+use satoru::callback::callback_utils::get_saved_callback_contract;
+use satoru::utils::span32::{Span32, Array32Trait};
+use satoru::nonce::nonce_utils::get_next_key;
+use integer::BoundedInt;
/// Creates a liquidation order for a position.
/// # Arguments
@@ -24,6 +31,49 @@ fn create_liquidation_order(
collateral_token: ContractAddress,
is_long: bool
) -> felt252 {
- // TODO
- 0
+ let key = get_position_key(account, market, collateral_token, is_long);
+ let position = data_store.get_position(key);
+ let callback_contract = get_saved_callback_contract(data_store, account, market);
+ let acceptable_price = if position.is_long {
+ 0
+ } else {
+ BoundedInt::::max()
+ };
+ let callback_gas_limit = data_store.get_u256(keys::max_callback_gas_limit());
+ let swap_path = Array32Trait::::span32(@ArrayTrait::new());
+ let updated_at_block = starknet::info::get_block_number();
+ let size_delta_usd = position.size_in_usd;
+ let trigger_price = 0;
+ let min_output_amount = 0;
+
+ let order = Order {
+ key,
+ order_type: OrderType::Liquidation,
+ decrease_position_swap_type: DecreasePositionSwapType::SwapPnlTokenToCollateralToken,
+ account,
+ receiver: account,
+ callback_contract,
+ ui_fee_receiver: 0.try_into().unwrap(),
+ market,
+ initial_collateral_token: position.collateral_token,
+ swap_path,
+ size_delta_usd,
+ initial_collateral_delta_amount: 0,
+ trigger_price,
+ acceptable_price,
+ execution_fee: 0,
+ callback_gas_limit,
+ min_output_amount: 0,
+ updated_at_block,
+ is_long: position.is_long,
+ is_frozen: false,
+ };
+ let nonce_key = get_next_key(data_store);
+ data_store.set_order(nonce_key, order);
+ event_emitter
+ .emit_order_updated(
+ nonce_key, size_delta_usd, acceptable_price, trigger_price, min_output_amount
+ );
+
+ nonce_key
}
diff --git a/src/market/error.cairo b/src/market/error.cairo
index 30d91b56..321d0988 100644
--- a/src/market/error.cairo
+++ b/src/market/error.cairo
@@ -1,22 +1,149 @@
mod MarketError {
use starknet::ContractAddress;
-
const MARKET_NOT_FOUND: felt252 = 'market_not_found';
const DIVISOR_CANNOT_BE_ZERO: felt252 = 'zero_divisor';
const INVALID_MARKET_PARAMS: felt252 = 'invalid_market_params';
const OPEN_INTEREST_CANNOT_BE_UPDATED_FOR_SWAP_ONLY_MARKET: felt252 =
'oi_not_updated_swap_only_market';
- const MAX_OPEN_INTEREST_EXCEEDED: felt252 = 'max_open_interest_exceeded';
+ const INVALID_SWAP_MARKET: felt252 = 'invalid_swap_market';
+ const EMPTY_ADDRESS_IN_MARKET_TOKEN_BALANCE_VALIDATION: felt252 =
+ 'empty_addr_market_balance_val';
+ const EMPTY_ADDRESS_TOKEN_BALANCE_VAL: felt252 = 'empty_addr_token_balance_val';
+ const INVALID_MARKET_TOKEN_BALANCE: felt252 = 'invalid_market_token_balance';
const INVALID_POSITION_MARKET: felt252 = 'invalid_position_market';
const INVALID_COLLATERAL_TOKEN_FOR_MARKET: felt252 = 'invalid_coll_token_for_market';
-
+ const UNABLE_TO_GET_OPPOSITE_TOKEN: felt252 = 'unable_to_get_opposite_token';
const EMPTY_MARKET: felt252 = 'empty_market';
- const DISABLED_MARKET: felt252 = 'disabled_market';
+ const COLLATERAL_ALREADY_CLAIMED: felt252 = 'collateral_already_claimed';
+
+ fn DISABLED_MARKET(is_market_disabled: bool) {
+ panic(array!['minimum_position_size', is_market_disabled.into()])
+ }
+
+ fn EMPTY_MARKET_TOKEN_SUPPLY(supply: u256) {
+ panic(
+ array!['empty_market_token_supply', supply.try_into().expect('u256 into felt failed')]
+ )
+ }
+
+ fn INVALID_MARKET_COLLATERAL_TOKEN(market: ContractAddress, token: ContractAddress) {
+ panic(array!['invalid_market_collateral_token', market.into(), token.into()])
+ }
+
+ fn UNABLE_TO_GET_FUNDING_FACTOR_EMPTY_OPEN_INTEREST(total_open_interest: u256) {
+ panic(
+ array![
+ 'unable_to_get_funding_factor',
+ total_open_interest.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn MAX_SWAP_PATH_LENGTH_EXCEEDED(token_swap_path_length: u32, max_swap_path_length: u256) {
+ panic(
+ array![
+ 'max_swap_path_length_exceeded',
+ token_swap_path_length.into(),
+ max_swap_path_length.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn PNL_EXCEEDED_FOR_LONGS(is_pnl_factor_exceeded_for_longs: bool) {
+ panic(array!['pnl_exceeded_for_longs', is_pnl_factor_exceeded_for_longs.into()])
+ }
+
+ fn PNL_EXCEEDED_FOR_SHORTS(is_pnl_factor_exceeded_for_shorts: bool) {
+ panic(array!['pnl_exceeded_for_shorts', is_pnl_factor_exceeded_for_shorts.into()])
+ }
+
+ fn UI_FEE_FACTOR_EXCEEDED(ui_fee_factor: u256, max_ui_fee_factor: u256) {
+ panic(
+ array![
+ 'ui_fee_factor_exceeded',
+ ui_fee_factor.try_into().expect('u256 into felt failed'),
+ max_ui_fee_factor.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn INVALID_MARKET_TOKEN_BALANCE_FOR_COLLATERAL_AMOUNT(balance: u256, collateral_amount: u256) {
+ panic(
+ array![
+ 'invalid_mrkt_tkn_balance_col',
+ balance.try_into().expect('u256 into felt failed'),
+ collateral_amount.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn INVALID_MARKET_TOKEN_BALANCE_FOR_CLAIMABLE_FUNDING(
+ balance: u256, claimable_funding_fee_amount: u256
+ ) {
+ panic(
+ array![
+ 'invalid_mrkt_tkn_balance_clm',
+ balance.try_into().expect('u256 into felt failed'),
+ claimable_funding_fee_amount.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn UNABLE_TO_GET_BORROWING_FACTOR_EMPTY_POOL_USD(pool_usd: u256) {
+ panic(
+ array![
+ 'unable_to_get_borrowing_factor',
+ pool_usd.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn MAX_OPEN_INTEREST_EXCEDEED(open_interest: u256, max_open_interest: u256) {
+ panic(
+ array![
+ 'max_open_interest_exceeded',
+ open_interest.try_into().expect('u256 into felt failed'),
+ max_open_interest.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn UNABLE_TO_GET_CACHED_TOKEN_PRICE(token_in: ContractAddress, market_token: ContractAddress) {
+ panic(array!['unable_to_get_cached_token_pri', token_in.into(), market_token.into()])
+ }
+
+ fn MAX_POOL_AMOUNT_EXCEEDED(pool_amount: u256, max_pool_amount: u256) {
+ panic(
+ array![
+ 'max_pool_amount_exceeded',
+ pool_amount.try_into().expect('u256 into felt failed'),
+ max_pool_amount.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn INSUFFICIENT_RESERVE(reserve: u256, amount: u256) {
+ panic(
+ array![
+ 'insufficient_reserve',
+ reserve.try_into().expect('u256 into felt failed'),
+ amount.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
+
+ fn UNEXCEPTED_BORROWING_FACTOR(borrowing_factor: u256, next: u256) {
+ panic(
+ array![
+ 'unexpected_borrowing_factor',
+ borrowing_factor.try_into().expect('u256 into felt failed'),
+ next.try_into().expect('u256 into felt failed')
+ ]
+ )
+ }
- fn UNABLE_TO_GET_CACHED_TOKEN_PRICE(token_in: ContractAddress) {
- let mut data = array!['invalid token in'];
- data.append(token_in.into());
- panic(data)
+ fn UNEXCEPTED_TOKEN(token: ContractAddress) {
+ panic(array!['unexpected_token', token.into()])
}
}
diff --git a/src/market/market.cairo b/src/market/market.cairo
index 2a2c01f7..db93cae9 100644
--- a/src/market/market.cairo
+++ b/src/market/market.cairo
@@ -39,7 +39,7 @@ use zeroable::Zeroable;
use satoru::market::error::MarketError;
use satoru::market::market_token::{IMarketTokenDispatcher, IMarketTokenDispatcherTrait};
-/// Deriving the `storage_access::StorageAccess` trait
+/// Deriving the `storage_access::Store` trait
/// allows us to store the `Market` struct in a contract's storage.
/// We use `Copy` but this is inneficient.
/// TODO: Optimize this.
diff --git a/src/market/market_event_utils.cairo b/src/market/market_event_utils.cairo
deleted file mode 100644
index a8be79cf..00000000
--- a/src/market/market_event_utils.cairo
+++ /dev/null
@@ -1,12 +0,0 @@
-use starknet::ContractAddress;
-
-use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
-use satoru::market::market_pool_value_info::MarketPoolValueInfo;
-
-fn emit_market_pool_value_info(
- event_emitter: IEventEmitterDispatcher,
- market: ContractAddress,
- props: MarketPoolValueInfo,
- market_tokens_supply: u128
-) {}
-
diff --git a/src/market/market_factory.cairo b/src/market/market_factory.cairo
index 25c88935..156ca797 100644
--- a/src/market/market_factory.cairo
+++ b/src/market/market_factory.cairo
@@ -48,7 +48,6 @@ mod MarketFactory {
use starknet::syscalls::deploy_syscall;
use poseidon::poseidon_hash_span;
- use debug::PrintTrait;
// Local imports.
use satoru::role::role;
@@ -103,7 +102,7 @@ mod MarketFactory {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl MarketFactory of super::IMarketFactory {
fn create_market(
ref self: ContractState,
@@ -124,14 +123,16 @@ mod MarketFactory {
);
// Deploy the `MarketToken` contract.
- // Contructor arguments: [role_store_address].
- let mut constructor_calldata = array![];
- constructor_calldata.append(self.role_store.read().contract_address.into());
+ // Contructor arguments: [role_store_address, data_store_address].
+ let mut constructor_calldata = array![
+ self.role_store.read().contract_address.into(),
+ self.data_store.read().contract_address.into()
+ ];
// Deploy the contract with the `deploy_syscall`.
let (market_token_deployed_address, return_data) = deploy_syscall(
self.market_token_class_hash.read(), salt, constructor_calldata.span(), false
)
- .unwrap();
+ .expect('failed to deploy market');
// Create the market.
let market = Market {
diff --git a/src/market/market_pool_value_info.cairo b/src/market/market_pool_value_info.cairo
index 3f39cb07..9cdb60e6 100644
--- a/src/market/market_pool_value_info.cairo
+++ b/src/market/market_pool_value_info.cairo
@@ -1,27 +1,29 @@
+use satoru::utils::i256::i256;
+
/// Struct to store MarketPoolValue infos.
#[derive(Default, Drop, Copy, starknet::Store, Serde)]
struct MarketPoolValueInfo {
/// The pool value.
- pool_value: u128, // TODO replace with i128 when it derives Store
+ pool_value: i256,
/// The pending pnl of long positions.
- long_pnl: u128, // TODO replace with i128 when it derives Store
+ long_pnl: i256,
/// The pending pnl of short positions
- short_pnl: u128, // TODO replace with i128 when it derives Store
+ short_pnl: i256,
/// The net pnl of long and short positions.
- net_pnl: u128, // TODO replace with i128 when it derives Store
+ net_pnl: i256,
/// The amount of long token in the pool.
- long_token_amount: u128,
+ long_token_amount: u256,
/// The amount of short token in the pool.
- short_token_amount: u128,
+ short_token_amount: u256,
/// The USD value of the long tokens in the pool.
- long_token_usd: u128,
+ long_token_usd: u256,
/// The USD value of the short tokens in the pool.
- short_token_usd: u128,
+ short_token_usd: u256,
/// The total pending borrowing fees for the market.
- total_borrowing_fees: u128,
+ total_borrowing_fees: u256,
/// The pool factor for borrowing fees.
- borrowing_fee_pool_factor: u128,
+ borrowing_fee_pool_factor: u256,
/// The amount of tokens in the impact pool.
- impact_pool_amount: u128,
+ impact_pool_amount: u256,
}
diff --git a/src/market/market_store_utils.cairo b/src/market/market_store_utils.cairo
new file mode 100644
index 00000000..5cd25bfb
--- /dev/null
+++ b/src/market/market_store_utils.cairo
@@ -0,0 +1,53 @@
+use poseidon::poseidon_hash_span;
+use starknet::{ContractAddress, get_block_timestamp};
+
+// Local imports.
+use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
+use satoru::data::keys;
+use satoru::market::market::Market;
+use satoru::utils::hash::hash_poseidon_single;
+
+fn market_salt() -> felt252 {
+ hash_poseidon_single('MARKET_SALT')
+}
+
+fn market_key() -> felt252 {
+ hash_poseidon_single('MARKET_KEY')
+}
+
+fn market_token() -> felt252 {
+ hash_poseidon_single('MARKET_TOKEN')
+}
+
+fn index_token() -> felt252 {
+ hash_poseidon_single('INDEX_TOKEN')
+}
+
+fn long_token() -> felt252 {
+ hash_poseidon_single('LONG_TOKEN')
+}
+
+fn short_token() -> felt252 {
+ hash_poseidon_single('SHORT_TOKEN')
+}
+
+fn get(data_store: IDataStoreDispatcher, key: ContractAddress) -> Market {
+ let market = data_store.get_market(key);
+ if market.market_token.is_zero() {
+ return market;
+ }
+
+ let hash = poseidon_hash_span(array![key.into(), market_token()].span());
+ let market_token = data_store.get_address(hash);
+
+ let hash = poseidon_hash_span(array![key.into(), index_token()].span());
+ let index_token = data_store.get_address(hash);
+
+ let hash = poseidon_hash_span(array![key.into(), long_token()].span());
+ let long_token = data_store.get_address(hash);
+
+ let hash = poseidon_hash_span(array![key.into(), short_token()].span());
+ let short_token = data_store.get_address(hash);
+
+ Market { market_token, index_token, long_token, short_token }
+}
diff --git a/src/market/market_token.cairo b/src/market/market_token.cairo
index 58864c96..90da10cf 100644
--- a/src/market/market_token.cairo
+++ b/src/market/market_token.cairo
@@ -7,16 +7,23 @@ trait IMarketToken {
fn name(self: @TState) -> felt252;
fn symbol(self: @TState) -> felt252;
fn decimals(self: @TState) -> u8;
- fn total_supply(self: @TState) -> u128;
- fn balance_of(self: @TState, account: ContractAddress) -> u128;
- fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u128;
- fn transfer(ref self: TState, recipient: ContractAddress, amount: u128) -> bool;
+ fn total_supply(self: @TState) -> u256;
+ fn balance_of(self: @TState, account: ContractAddress) -> u256;
+ fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
+ fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
- ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u128
+ ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
- fn approve(ref self: TState, spender: ContractAddress, amount: u128) -> bool;
- fn mint(ref self: TState, recipient: ContractAddress, amount: u128);
- fn burn(ref self: TState, recipient: ContractAddress, amount: u128);
+ fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
+ fn mint(ref self: TState, recipient: ContractAddress, amount: u256);
+ fn burn(ref self: TState, recipient: ContractAddress, amount: u256);
+ fn transfer_out(
+ ref self: TState,
+ sender: ContractAddress,
+ token: ContractAddress,
+ receiver: ContractAddress,
+ amount: u256,
+ );
}
#[starknet::contract]
@@ -26,9 +33,9 @@ mod MarketToken {
use starknet::get_caller_address;
use zeroable::Zeroable;
- use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
use satoru::role::role;
use satoru::bank::bank::{Bank, IBank};
+ use satoru::role::role_module::{RoleModule, IRoleModule};
use super::IMarketToken;
@@ -38,12 +45,11 @@ mod MarketToken {
#[storage]
struct Storage {
- role_store: IRoleStoreDispatcher,
name: felt252,
symbol: felt252,
- total_supply: u128,
- balances: LegacyMap,
- allowances: LegacyMap<(ContractAddress, ContractAddress), u128>,
+ total_supply: u256,
+ balances: LegacyMap,
+ allowances: LegacyMap<(ContractAddress, ContractAddress), u256>,
}
#[event]
@@ -57,30 +63,32 @@ mod MarketToken {
struct Transfer {
from: ContractAddress,
to: ContractAddress,
- value: u128
+ value: u256
}
#[derive(Drop, starknet::Event)]
struct Approval {
owner: ContractAddress,
spender: ContractAddress,
- value: u128
+ value: u256
}
#[constructor]
- fn constructor(ref self: ContractState, role_store_address: ContractAddress) {
+ fn constructor(
+ ref self: ContractState,
+ role_store_address: ContractAddress,
+ data_store_address: ContractAddress
+ ) {
self.initializer(NAME, SYMBOL);
- //Might need to inherit bank.
- // let mut bank: Bank::ContractState = Bank::unsafe_new_contract_state();
- // IBank::initialize(ref bank, data_store_address, role_store_address)
- self.role_store.write(IRoleStoreDispatcher { contract_address: role_store_address });
+
+ let mut bank: Bank::ContractState = Bank::unsafe_new_contract_state();
+ IBank::initialize(ref bank, data_store_address, role_store_address);
}
//
// External
//
-
- #[external(v0)]
+ #[abi(embed_v0)]
impl MarketTokenImpl of IMarketToken {
fn name(self: @ContractState) -> felt252 {
self.name.read()
@@ -94,21 +102,21 @@ mod MarketToken {
DECIMALS
}
- fn total_supply(self: @ContractState) -> u128 {
+ fn total_supply(self: @ContractState) -> u256 {
self.total_supply.read()
}
- fn balance_of(self: @ContractState, account: ContractAddress) -> u128 {
+ fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
self.balances.read(account)
}
fn allowance(
self: @ContractState, owner: ContractAddress, spender: ContractAddress
- ) -> u128 {
+ ) -> u256 {
self.allowances.read((owner, spender))
}
- fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u128) -> bool {
+ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
let sender = get_caller_address();
self._transfer(sender, recipient, amount);
true
@@ -118,7 +126,7 @@ mod MarketToken {
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
- amount: u128
+ amount: u256
) -> bool {
let caller = get_caller_address();
self._spend_allowance(sender, caller, amount);
@@ -126,49 +134,63 @@ mod MarketToken {
true
}
- fn approve(ref self: ContractState, spender: ContractAddress, amount: u128) -> bool {
+ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {
let caller = get_caller_address();
self._approve(caller, spender, amount);
true
}
- fn mint(ref self: ContractState, recipient: ContractAddress, amount: u128) {
+ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
// Check that the caller has permission to set the value.
- self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
+ // let mut role_module: RoleModule::ContractState =
+ // RoleModule::unsafe_new_contract_state();
+ // role_module.only_controller();
self._mint(recipient, amount);
}
- fn burn(ref self: ContractState, recipient: ContractAddress, amount: u128) {
+ fn burn(ref self: ContractState, recipient: ContractAddress, amount: u256) {
// Check that the caller has permission to set the value.
- self.role_store.read().assert_only_role(get_caller_address(), role::CONTROLLER);
+ let mut role_module: RoleModule::ContractState =
+ RoleModule::unsafe_new_contract_state();
+ role_module.only_controller();
self._burn(recipient, amount);
}
+ fn transfer_out(
+ ref self: ContractState,
+ sender: ContractAddress,
+ token: ContractAddress,
+ receiver: ContractAddress,
+ amount: u256,
+ ) {
+ let mut bank: Bank::ContractState = Bank::unsafe_new_contract_state();
+ IBank::transfer_out(ref bank, sender, token, receiver, amount);
+ }
}
#[external(v0)]
fn increase_allowance(
- ref self: ContractState, spender: ContractAddress, added_value: u128
+ ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
self._increase_allowance(spender, added_value)
}
#[external(v0)]
fn increaseAllowance(
- ref self: ContractState, spender: ContractAddress, addedValue: u128
+ ref self: ContractState, spender: ContractAddress, addedValue: u256
) -> bool {
increase_allowance(ref self, spender, addedValue)
}
#[external(v0)]
fn decrease_allowance(
- ref self: ContractState, spender: ContractAddress, subtracted_value: u128
+ ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
self._decrease_allowance(spender, subtracted_value)
}
#[external(v0)]
fn decreaseAllowance(
- ref self: ContractState, spender: ContractAddress, subtractedValue: u128
+ ref self: ContractState, spender: ContractAddress, subtractedValue: u256
) -> bool {
decrease_allowance(ref self, spender, subtractedValue)
}
@@ -185,7 +207,7 @@ mod MarketToken {
}
fn _increase_allowance(
- ref self: ContractState, spender: ContractAddress, added_value: u128
+ ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
let caller = get_caller_address();
self._approve(caller, spender, self.allowances.read((caller, spender)) + added_value);
@@ -193,7 +215,7 @@ mod MarketToken {
}
fn _decrease_allowance(
- ref self: ContractState, spender: ContractAddress, subtracted_value: u128
+ ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
let caller = get_caller_address();
self
@@ -203,14 +225,14 @@ mod MarketToken {
true
}
- fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u128) {
+ fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
assert(!recipient.is_zero(), 'ERC20: mint to 0');
self.total_supply.write(self.total_supply.read() + amount);
self.balances.write(recipient, self.balances.read(recipient) + amount);
self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount });
}
- fn _burn(ref self: ContractState, account: ContractAddress, amount: u128) {
+ fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) {
assert(!account.is_zero(), 'ERC20: burn from 0');
self.total_supply.write(self.total_supply.read() - amount);
self.balances.write(account, self.balances.read(account) - amount);
@@ -218,7 +240,7 @@ mod MarketToken {
}
fn _approve(
- ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u128
+ ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
assert(!owner.is_zero(), 'ERC20: approve from 0');
assert(!spender.is_zero(), 'ERC20: approve to 0');
@@ -230,7 +252,7 @@ mod MarketToken {
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
- amount: u128
+ amount: u256
) {
assert(!sender.is_zero(), 'ERC20: transfer from 0');
assert(!recipient.is_zero(), 'ERC20: transfer to 0');
@@ -240,7 +262,7 @@ mod MarketToken {
}
fn _spend_allowance(
- ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u128
+ ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
let current_allowance = self.allowances.read((owner, spender));
if current_allowance != BoundedInt::max() {
diff --git a/src/market/market_utils.cairo b/src/market/market_utils.cairo
index 1174848f..267dba8a 100644
--- a/src/market/market_utils.cairo
+++ b/src/market/market_utils.cairo
@@ -2,25 +2,36 @@
// IMPORTS
// *************************************************************************
// Core lib imports.
-use starknet::{ContractAddress, get_block_timestamp};
-use result::ResultTrait;
-
-use debug::PrintTrait;
-use zeroable::Zeroable;
-
+use starknet::{ContractAddress, get_caller_address, get_block_timestamp, contract_address_const};
// Local imports.
+use satoru::utils::calc::roundup_magnitude_division;
+use satoru::bank::bank::{IBankDispatcher, IBankDispatcherTrait};
use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
use satoru::chain::chain::{IChainDispatcher, IChainDispatcherTrait};
+use satoru::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
+use satoru::chain::chain::Chain;
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
use satoru::data::keys;
+use satoru::event::event_emitter;
use satoru::market::{
market::Market, error::MarketError, market_pool_value_info::MarketPoolValueInfo,
- market_token::{IMarketTokenDispatcher, IMarketTokenDispatcherTrait}
+ market_store_utils, market_token::{IMarketTokenDispatcher, IMarketTokenDispatcherTrait}
};
+use satoru::utils::span32::{Span32, Span32Trait};
use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait};
+use satoru::oracle::oracle::{Oracle, SetPricesParams};
+use satoru::oracle::oracle_store::{IOracleStoreDispatcher, IOracleStoreDispatcherTrait};
use satoru::price::price::{Price, PriceTrait};
-use satoru::utils::span32::Span32;
-use satoru::utils::i128::{StoreI128, u128_to_i128, I128Serde, I128Div, I128Mul};
+use satoru::utils::calc;
+use satoru::utils::precision::{FLOAT_PRECISION, FLOAT_PRECISION_SQRT};
+use satoru::utils::precision::{mul_div_roundup, to_factor_ival, apply_factor_u256, to_factor};
+use satoru::utils::precision;
+use satoru::utils::calc::{roundup_division, to_signed, sum_return_int_256, to_unsigned};
+use satoru::position::position::Position;
+use satoru::utils::{i256::{i256, i256_neg}, error_utils};
+use satoru::utils::precision::{apply_exponent_factor, float_to_wei, mul_div};
+use satoru::data::keys::{skip_borrowing_fee_for_smaller_side, max_swap_path_length};
+
/// Struct to store the prices of tokens of a market.
/// # Params
/// * `indexTokenPrice` - Price of the market's index token.
@@ -34,156 +45,402 @@ struct MarketPrices {
short_token_price: Price,
}
-#[derive(Drop, starknet::Store, Serde)]
+#[derive(Default, Drop, starknet::Store, Serde)]
struct CollateralType {
- long_token: u128,
- short_token: u128,
+ long_token: u256,
+ short_token: u256,
}
-#[derive(Drop, starknet::Store, Serde)]
+#[derive(Default, Drop, starknet::Store, Serde)]
struct PositionType {
long: CollateralType,
short: CollateralType,
}
-#[derive(Drop, starknet::Store, Serde)]
+#[derive(Default, Drop, starknet::Store, Serde)]
struct GetNextFundingAmountPerSizeResult {
longs_pay_shorts: bool,
- funding_factor_per_second: u128,
+ funding_factor_per_second: u256,
funding_fee_amount_per_size_delta: PositionType,
claimable_funding_amount_per_size_delta: PositionType,
}
+struct GetExpectedMinTokenBalanceCache {
+ pool_amount: u256,
+ swap_impact_pool_amount: u256,
+ claimable_collateral_amount: u256,
+ claimable_fee_amount: u256,
+ claimable_ui_fee_amount: u256,
+ affiliate_reward_amount: u256,
+}
+
+/// Get the market token price.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to get the market token price for.
+/// * `long_token_price` - The price of the long token.
+/// * `short_token_price` - The price of the short token.
+/// * `index_token_price` - The price of the index token.
+/// * `maximize` - Whether to maximize or minimize the market token price.
+/// # Returns
+/// The market token price.
+fn get_market_token_price(
+ data_store: IDataStoreDispatcher,
+ market: Market,
+ index_token_price: Price,
+ long_token_price: Price,
+ short_token_price: Price,
+ pnl_factor_type: felt252,
+ maximize: bool
+) -> (i256, MarketPoolValueInfo) {
+ let supply = get_market_token_supply(
+ IMarketTokenDispatcher { contract_address: market.market_token }
+ );
+
+ let pool_value_info = get_pool_value_info(
+ data_store,
+ market,
+ index_token_price,
+ long_token_price,
+ short_token_price,
+ pnl_factor_type,
+ maximize
+ );
+
+ // if the supply is zero then treat the market token price as 1 USD
+ if supply == 0 {
+ return (calc::to_signed(precision::FLOAT_PRECISION, true), pool_value_info);
+ }
+
+ if pool_value_info.pool_value == Zeroable::zero() {
+ return (Zeroable::zero(), pool_value_info);
+ }
+
+ let market_token_price = precision::mul_div_inum(
+ precision::WEI_PRECISION, pool_value_info.pool_value, supply
+ );
+ (market_token_price, pool_value_info)
+}
+
+/// Gets the total supply of the marketToken.
+/// # Arguments
+/// * `market_token` - The market token whose total supply is to be retrieved.
+/// # Returns
+/// The total supply of the given marketToken.
+fn get_market_token_supply(market_token: IMarketTokenDispatcher) -> u256 {
+ market_token.total_supply()
+}
+
+/// Get the opposite token of the market
+/// if the input_token is the token_long return the short_token and vice versa
+/// # Arguments
+/// * `market` - The market to validate the open interest for.
+/// * `token` - The input_token.
+/// # Returns
+/// The opposite token.
+fn get_opposite_token(input_token: ContractAddress, market: @Market) -> ContractAddress {
+ if input_token == *market.long_token {
+ *market.short_token
+ } else if input_token == *market.short_token {
+ *market.long_token
+ } else {
+ panic(
+ array![
+ MarketError::UNABLE_TO_GET_OPPOSITE_TOKEN,
+ input_token.into(),
+ (*market.market_token).into()
+ ]
+ )
+ }
+}
+
+fn validate_swap_market_with_address(
+ data_store: IDataStoreDispatcher, market_address: ContractAddress
+) {
+ let market = data_store.get_market(market_address);
+ validate_swap_market(data_store, market);
+}
+
+/// Validata the swap market.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to validate the open interest for.
+fn validate_swap_market(data_store: IDataStoreDispatcher, market: Market) {
+ validate_enabled_market(data_store, market);
+
+ if market.long_token == market.short_token {
+ panic(array![MarketError::INVALID_SWAP_MARKET, market.market_token.into()])
+ }
+}
+
// @dev get the token price from the stored MarketPrices
// @param token the token to get the price for
// @param the market values
// @param the market token prices
// @return the token price from the stored MarketPrices
fn get_cached_token_price(token: ContractAddress, market: Market, prices: MarketPrices) -> Price {
- if (token == market.long_token) {
+ if token == market.long_token {
prices.long_token_price
- } else if (token == market.short_token) {
+ } else if token == market.short_token {
prices.short_token_price
- } else if (token == market.index_token) {
+ } else if token == market.index_token {
prices.index_token_price
} else {
- MarketError::UNABLE_TO_GET_CACHED_TOKEN_PRICE(token);
- prices.index_token_price //todo : remove
+ MarketError::UNABLE_TO_GET_CACHED_TOKEN_PRICE(token, market.market_token);
+ Default::default()
}
}
-fn get_swap_impact_amount_with_cap(
- dataStore: IDataStoreDispatcher,
- market: ContractAddress,
- token: ContractAddress,
- tokenPrice: Price,
- priceImpactUsd: i128 //TODO : check u128
-) -> i128 { //Todo : check u128
- //TODO
- return 0;
+/// Returns the primary prices for the market tokens.
+/// # Parameters
+/// - `oracle`: The Oracle instance.
+/// - `market`: The market values.
+fn get_market_prices(oracle: IOracleDispatcher, market: Market) -> MarketPrices {
+ MarketPrices {
+ index_token_price: oracle.get_primary_price(market.index_token),
+ long_token_price: oracle.get_primary_price(market.long_token),
+ short_token_price: oracle.get_primary_price(market.short_token),
+ }
}
-/// Get the long and short open interest for a market based on the collateral token used.
+/// Get the usd value of either the long or short tokens in the pool
+/// without accounting for the pnl of open positions
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the open interest for.
-/// * `collateral_token` - The collateral token to check.
-/// * `is_long` - Whether to get the long or short open interest.
-/// * `divisor` - The divisor to use for the open interest.
-fn get_open_interest(
+/// * `market` - The market values.
+/// * `prices` - The prices of the market tokens.
+/// * `is_long` - Whether to return the value for the long or short token.
+/// * `maximize` - Whether to maximize or minimize the pool value.
+/// # Returns
+/// The usd value of either the long or short tokens in the pool.
+fn get_pool_usd_without_pnl(
data_store: IDataStoreDispatcher,
- market: ContractAddress,
- collateral_token: ContractAddress,
+ market: @Market,
+ prices: @MarketPrices,
is_long: bool,
- divisor: u128
-) -> u128 {
- assert(divisor != 0, MarketError::DIVISOR_CANNOT_BE_ZERO);
- let key = keys::open_interest_key(market, collateral_token, is_long);
- data_store.get_u128(key) / divisor
+ maximize: bool
+) -> u256 {
+ let token = if is_long {
+ *market.long_token
+ } else {
+ *market.short_token
+ };
+ // note that if it is a single token market, the poolAmount returned will be
+ // the amount of tokens in the pool divided by 2
+ let pool_amount = get_pool_amount(data_store, market, token);
+ let token_price = if maximize {
+ if is_long {
+ prices.long_token_price.max
+ } else {
+ prices.short_token_price.max
+ }
+ } else {
+ if is_long {
+ prices.long_token_price.min
+ } else {
+ prices.short_token_price.min
+ }
+ };
+ pool_amount * (*token_price)
}
-/// Get the long and short open interest for a market.
+/// Get the USD value of a pool.
+/// The value of a pool is the worth of the liquidity provider tokens in the pool - pending trader pnl.
+/// We use the token index prices to calculate this and ignore price impact since if all positions were closed the
+/// net price impact should be zero.
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the open interest for.
+/// * `market` - The market values.
+/// * `index_token_price` - The price of the index token.
+/// * `long_token_price` - The price of the long token.
+/// * `short_token_price` - The price of the short token.
+/// * `maximize` - Whether to maximize or minimize the pool value.
/// # Returns
-/// The long and short open interest for a market.
-fn get_open_interest_for_market(data_store: IDataStoreDispatcher, market: @Market) -> u128 {
- // Get the open interest for the long token as collateral.
- let long_open_interest = get_open_interest_for_market_is_long(data_store, market, true);
- // Get the open interest for the short token as collateral.
- let short_open_interest = get_open_interest_for_market_is_long(data_store, market, false);
- long_open_interest + short_open_interest
+/// The value information of a pool.
+fn get_pool_value_info(
+ data_store: IDataStoreDispatcher,
+ market: Market,
+ index_token_price: Price,
+ long_token_price: Price,
+ short_token_price: Price,
+ pnl_factor_type: felt252,
+ maximize: bool
+) -> MarketPoolValueInfo {
+ let mut result: MarketPoolValueInfo = Default::default();
+
+ result.long_token_amount = get_pool_amount(data_store, @market, market.long_token);
+ result.short_token_amount = get_pool_amount(data_store, @market, market.short_token);
+
+ result.long_token_usd = result.long_token_amount * long_token_price.pick_price(maximize);
+ result.short_token_usd = result.short_token_amount * short_token_price.pick_price(maximize);
+
+ result.pool_value = calc::to_signed(result.long_token_usd + result.short_token_usd, true);
+
+ let prices = MarketPrices { index_token_price, long_token_price, short_token_price };
+
+ result
+ .total_borrowing_fees = get_total_pending_borrowing_fees(data_store, market, prices, true);
+
+ result
+ .total_borrowing_fees +=
+ get_total_pending_borrowing_fees(data_store, market, prices, false);
+
+ result.borrowing_fee_pool_factor = precision::FLOAT_PRECISION
+ - data_store.get_u256(keys::borrowing_fee_receiver_factor());
+
+ let value = precision::apply_factor_u256(
+ result.total_borrowing_fees, result.borrowing_fee_pool_factor
+ );
+ result.pool_value += calc::to_signed(value, true);
+
+ // !maximize should be used for net pnl as a larger pnl leads to a smaller pool value
+ // and a smaller pnl leads to a larger pool value
+ //
+ // while positions will always be closed at the less favourable price
+ // using the inverse of maximize for the getPnl calls would help prevent
+ // gaming of market token values by increasing the spread
+ //
+ // liquidations could be triggerred by manipulating a large spread but
+ // that should be more difficult to execute
+
+ result.long_pnl = get_pnl(data_store, @market, @index_token_price, true, !maximize);
+
+ result
+ .long_pnl =
+ get_capped_pnl(
+ data_store,
+ market.market_token,
+ true,
+ result.long_pnl,
+ result.long_token_usd,
+ pnl_factor_type,
+ );
+
+ result.short_pnl = get_pnl(data_store, @market, @index_token_price, false, !maximize);
+
+ result
+ .short_pnl =
+ get_capped_pnl(
+ data_store,
+ market.market_token,
+ false,
+ result.short_pnl,
+ result.short_token_usd,
+ pnl_factor_type,
+ );
+
+ result.net_pnl = result.long_pnl + result.short_pnl;
+ result.pool_value = result.pool_value - result.net_pnl;
+
+ result.impact_pool_amount = get_position_impact_pool_amount(data_store, market.market_token);
+ // use !maximize for pick_price since the impact_pool_usd is deducted from the pool_value
+ let impact_pool_usd = result.impact_pool_amount * index_token_price.pick_price(!maximize);
+
+ result.pool_value -= calc::to_signed(impact_pool_usd, true);
+
+ result
}
-/// Get the long and short open interest for a market.
+/// Get the net pending pnl for a market
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the open interest for.
-/// * `is_long` - Whether to get the long or short open interest.
+/// * `market` - The market to get the pending PNL for.
+/// * `index_token_price` - The price of the index token.
+/// * `maximize` - Whether to maximize or minimize the net PNL.
/// # Returns
-/// The long and short open interest for a market.
-fn get_open_interest_for_market_is_long(
- data_store: IDataStoreDispatcher, market: @Market, is_long: bool
-) -> u128 {
- // Get the pool divisor.
- let divisor = get_pool_divisor(*market.long_token, *market.short_token);
- // Get the open interest for the long token as collateral.
- let open_interest_using_long_token_as_collateral = get_open_interest(
- data_store, *market.market_token, *market.long_token, is_long, divisor
- );
- // Get the open interest for the short token as collateral.
- let open_interest_using_short_token_as_collateral = get_open_interest(
- data_store, *market.market_token, *market.short_token, is_long, divisor
- );
- // Return the sum of the open interests.
- open_interest_using_long_token_as_collateral + open_interest_using_short_token_as_collateral
+/// The net pending pnl for a market
+fn get_net_pnl(
+ data_store: IDataStoreDispatcher, market: @Market, index_token_price: @Price, maximize: bool
+) -> i256 {
+ let long_pnl = get_pnl(data_store, market, index_token_price, true, maximize);
+ let short_pnl = get_pnl(data_store, market, index_token_price, false, maximize);
+ long_pnl + short_pnl
}
-
-/// Get the long and short open interest in tokens for a market.
+/// Get the capped pending pnl for a market
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the open interest for.
-/// * `is_long` - Whether to get the long or short open interest.
+/// * `market` - The market to get the pending PNL for.
+/// * `is_long` - Whether to get the long or short pending PNL.
+/// * `pnl` - The uncapped pnl of the market.
+/// * `pool_usd` - The USD value of the pool.
+/// * `pnl_factor_type` - The pnl factor type to use.
/// # Returns
-/// The long and short open interest in tokens for a market based on the collateral token used.
-fn get_open_interest_in_tokens_for_market(
- data_store: IDataStoreDispatcher, market: @Market, is_long: bool,
-) -> u128 {
- // Get the pool divisor.
- let divisor = get_pool_divisor(*market.long_token, *market.short_token);
+/// The net pending pnl for a market
+fn get_capped_pnl(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ is_long: bool,
+ pnl: i256,
+ pool_usd: u256,
+ pnl_factor_type: felt252
+) -> i256 {
+ if pnl < Zeroable::zero() {
+ return pnl;
+ }
+ let max_pnl_factor = get_max_pnl_factor(data_store, pnl_factor_type, market, is_long);
+ let max_pnl = calc::to_signed(precision::apply_factor_u256(pool_usd, max_pnl_factor), true);
+ if pnl > max_pnl {
+ max_pnl
+ } else {
+ pnl
+ }
+}
- // Get the open interest for the long token as collateral.
- let open_interest_using_long_token_as_collateral = get_open_interest_in_tokens(
- data_store, *market.market_token, *market.long_token, is_long, divisor
- );
- // Get the open interest for the short token as collateral.
- let open_interest_using_short_token_as_collateral = get_open_interest_in_tokens(
- data_store, *market.market_token, *market.short_token, is_long, divisor
- );
- // Return the sum of the open interests.
- open_interest_using_long_token_as_collateral + open_interest_using_short_token_as_collateral
+fn get_pnl_with_u256_price(
+ data_store: IDataStoreDispatcher,
+ market: @Market,
+ index_token_price: u256,
+ is_long: bool,
+ maximize: bool
+) -> i256 {
+ let index_token_price_ = Price { min: index_token_price, max: index_token_price };
+ get_pnl(data_store, market, @index_token_price_, is_long, maximize)
}
-/// Get the long and short open interest in tokens for a market based on the collateral token used.
+/// Get the pending PNL for a market for either longs or shorts.
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the open interest for.
-/// * `collateral_token` - The collateral token to check.
-/// * `is_long` - Whether to get the long or short open interest.
-/// * `divisor` - The divisor to use for the open interest.
+/// * `market` - The market to get the pending PNL for.
+/// * `index_token_price` - The price of the index token.
+/// * `is_long` - Whether to get the long or short pending PNL.
+/// * `maximize` - Whether to maximize or minimize the net PNL.
/// # Returns
-/// The long and short open interest in tokens for a market based on the collateral token used.
-fn get_open_interest_in_tokens(
+/// The pending PNL for a market for either longs or shorts.
+fn get_pnl(
data_store: IDataStoreDispatcher,
- market: ContractAddress,
- collateral_token: ContractAddress,
+ market: @Market,
+ index_token_price: @Price,
is_long: bool,
- divisor: u128
-) -> u128 {
- data_store.get_u128(keys::open_interest_in_tokens_key(market, collateral_token, is_long))
- / divisor
+ maximize: bool
+) -> i256 {
+ // Get the open interest.
+ let open_interest = calc::to_signed(
+ get_open_interest_for_market_is_long(data_store, market, is_long), true
+ );
+ // Get the open interest in tokens.
+ let open_interest_in_tokens = get_open_interest_in_tokens_for_market(
+ data_store, market, is_long
+ );
+ // If either the open interest or the open interest in tokens is zero, return zero.
+ if open_interest == Zeroable::zero() || open_interest_in_tokens == 0 {
+ return Zeroable::zero();
+ }
+
+ // Pick the price for PNL.
+ let price = index_token_price.pick_price_for_pnl(is_long, maximize);
+
+ // `open_interest` is the cost of all positions, `open_interest_valu`e is the current worth of all positions.
+ let open_interest_value = calc::to_signed(open_interest_in_tokens * price, true);
+
+ // Return the PNL.
+ // If `is_long` is true, then the PNL is the difference between the current worth of all positions and the cost of all positions.
+ // If `is_long` is false, then the PNL is the difference between the cost of all positions and the current worth of all positions.
+ if is_long {
+ open_interest_value - open_interest
+ } else {
+ open_interest - open_interest_value
+ }
}
/// Get the amount of tokens in the pool
@@ -195,9 +452,10 @@ fn get_open_interest_in_tokens(
/// The amount of tokens in the pool.
fn get_pool_amount(
data_store: IDataStoreDispatcher, market: @Market, token_address: ContractAddress
-) -> u128 {
+) -> u256 {
let divisor = get_pool_divisor(*market.long_token, *market.short_token);
- data_store.get_u128(keys::pool_amount_key(*market.market_token, token_address)) / divisor
+ error_utils::check_division_by_zero(divisor, 'get_pool_amount');
+ data_store.get_u256(keys::pool_amount_key(*market.market_token, token_address)) / divisor
}
/// Get the maximum amount of tokens allowed to be in the pool.
@@ -211,8 +469,8 @@ fn get_max_pool_amount(
data_store: IDataStoreDispatcher,
market_address: ContractAddress,
token_address: ContractAddress
-) -> u128 {
- data_store.get_u128(keys::max_pool_amount_key(market_address, token_address))
+) -> u256 {
+ data_store.get_u256(keys::max_pool_amount_key(market_address, token_address))
}
/// Get the maximum open interest allowed for a market.
@@ -224,8 +482,8 @@ fn get_max_pool_amount(
/// The maximum open interest allowed for a market.
fn get_max_open_interest(
data_store: IDataStoreDispatcher, market_address: ContractAddress, is_long: bool
-) -> u128 {
- data_store.get_u128(keys::max_open_interest_key(market_address, is_long))
+) -> u256 {
+ data_store.get_u256(keys::max_open_interest_key(market_address, is_long))
}
/// Increment the claimable collateral amount.
@@ -239,30 +497,27 @@ fn get_max_open_interest(
/// * `delta` - The amount to increment by.
fn increment_claimable_collateral_amount(
data_store: IDataStoreDispatcher,
- chain: IChainDispatcher,
event_emitter: IEventEmitterDispatcher,
market_address: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- delta: u128
+ delta: u256
) {
- let divisor = data_store.get_u128(keys::claimable_collateral_time_divisor());
+ let divisor = data_store.get_u256(keys::claimable_collateral_time_divisor());
+ error_utils::check_division_by_zero(divisor, 'increment_claimable_collateral');
// Get current timestamp.
- let current_timestamp = chain.get_block_timestamp().into();
+ let current_timestamp = get_block_timestamp().into();
let time_key = current_timestamp / divisor;
// Increment the collateral amount for the account.
- let next_value = data_store
- .increment_u128(
- keys::claimable_collateral_amount_for_account_key(
- market_address, token, time_key, account
- ),
- delta
- );
+ let key = keys::claimable_collateral_amount_for_account_key(
+ market_address, token, time_key, account
+ );
+ let next_value = data_store.increment_u256(key, delta);
// Increment the total collateral amount for the market.
let next_pool_value = data_store
- .increment_u128(keys::claimable_collateral_amount_key(market_address, token), delta);
+ .increment_u256(keys::claimable_collateral_amount_key(market_address, token), delta);
// Emit event.
event_emitter
@@ -285,17 +540,17 @@ fn increment_claimable_funding_amount(
market_address: ContractAddress,
token: ContractAddress,
account: ContractAddress,
- delta: u128
+ delta: u256
) {
// Increment the funding amount for the account.
let next_value = data_store
- .increment_u128(
+ .increment_u256(
keys::claimable_funding_amount_by_account_key(market_address, token, account), delta
);
// Increment the total funding amount for the market.
let next_pool_value = data_store
- .increment_u128(keys::claimable_funding_amount_key(market_address, token), delta);
+ .increment_u256(keys::claimable_funding_amount_key(market_address, token), delta);
// Emit event.
event_emitter
@@ -304,65 +559,247 @@ fn increment_claimable_funding_amount(
);
}
-/// Get the pool divisor.
-/// This is used to divide the values of `get_pool_amount` and `get_open_interest`
-/// if the longToken and shortToken are the same, then these values have to be divided by two
-/// to avoid double counting
+/// Claim funding fees
/// # Arguments
-/// * `long_token` - The long token.
-/// * `short_token` - The short token.
-/// # Returns
-/// The pool divisor.
-fn get_pool_divisor(long_token: ContractAddress, short_token: ContractAddress) -> u128 {
- if long_token == short_token {
- 2
- } else {
- 1
- }
+/// * `data_store` - The data store to use.
+/// * `event_emitter` - The interface to interact with `EventEmitter` contract.
+/// * `market_address` - The market to claim for.
+/// * `token` - The token to claim.
+/// * `account` - The account to claim for.
+/// * `receiver` - The receiver to send the amount to.
+fn claim_funding_fees(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market_address: ContractAddress,
+ token: ContractAddress,
+ account: ContractAddress,
+ receiver: ContractAddress
+) -> u256 {
+ let key = keys::claimable_funding_amount_by_account_key(market_address, token, account);
+ let claimable_amount = data_store.get_u256(key);
+ data_store.set_u256(key, 0);
+
+ let next_pool_value = data_store
+ .decrement_u256(
+ keys::claimable_funding_amount_key(market_address, token), claimable_amount
+ );
+
+ // Transfer the amount to the receiver.
+ IBankDispatcher { contract_address: market_address }
+ .transfer_out(market_address, token, receiver, claimable_amount);
+
+ // Validate the market token balance.
+ validate_market_token_balance_with_address(data_store, market_address);
+
+ event_emitter
+ .emit_funding_fees_claimed(
+ market_address, token, account, receiver, claimable_amount, next_pool_value
+ );
+
+ claimable_amount
}
-/// Get the pending PNL for a market for either longs or shorts.
+/// Claim collateral
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to get the pending PNL for.
-/// * `index_token_price` - The price of the index token.
-/// * `is_long` - Whether to get the long or short pending PNL.
-/// * `maximize` - Whether to maximize or minimize the net PNL.
-/// # Returns
-/// The pending PNL for a market for either longs or shorts.
-fn get_pnl(
+/// * `event_emitter` - The interface to interact with `EventEmitter` contract.
+/// * `market_address` - The market to claim for.
+/// * `token` - The token to claim.
+/// * `time_key` - The time key.
+/// * `account` - The account to claim for.
+/// * `receiver` - The receiver to send the amount to.
+fn claim_collateral(
data_store: IDataStoreDispatcher,
- market: @Market,
- index_token_price: @Price,
- is_long: bool,
- maximize: bool
-) -> i128 {
- // Get the open interest.
- let open_interest = u128_to_i128(
- get_open_interest_for_market_is_long(data_store, market, is_long)
+ event_emitter: IEventEmitterDispatcher,
+ market_address: ContractAddress,
+ token: ContractAddress,
+ time_key: u256,
+ account: ContractAddress,
+ receiver: ContractAddress
+) -> u256 {
+ let key = keys::claimable_collateral_amount_for_account_key(
+ market_address, token, time_key, account
);
- // Get the open interest in tokens.
- let open_interest_in_tokens = get_open_interest_in_tokens_for_market(
- data_store, market, is_long
+ let claimable_amount = data_store.get_u256(key);
+ data_store.set_u256(key, 0);
+
+ let key = keys::claimable_collateral_factor_key(market_address, token, time_key);
+ let claimable_factor_for_time = data_store.get_u256(key);
+
+ let key = keys::claimable_collateral_factor_for_account_key(
+ market_address, token, time_key, account
);
- // If either the open interest or the open interest in tokens is zero, return zero.
- if open_interest == 0 || open_interest_in_tokens == 0 {
- return 0;
+ let claimable_factor_for_account = data_store.get_u256(key);
+
+ let claimable_factor = if claimable_factor_for_time > claimable_factor_for_account {
+ claimable_factor_for_time
+ } else {
+ claimable_factor_for_account
+ };
+
+ let key = keys::claimed_collateral_amount_key(market_address, token, time_key, account);
+ let claimed_amount = data_store.get_u256(key);
+
+ let adjusted_claimable_amount = precision::apply_factor_u256(
+ claimable_amount, claimable_factor
+ );
+ if adjusted_claimable_amount <= claimed_amount {
+ panic(
+ array![
+ MarketError::COLLATERAL_ALREADY_CLAIMED,
+ adjusted_claimable_amount.try_into().expect('u256 into felt failed'),
+ claimed_amount.try_into().expect('u256 into felt failed')
+ ]
+ )
}
- // Pick the price for PNL.
- let price = index_token_price.pick_price_for_pnl(is_long, maximize);
+ let amount_to_be_claimed = adjusted_claimable_amount - claimed_amount;
- // `open_interest` is the cost of all positions, `open_interest_valu`e is the current worth of all positions.
- let open_interest_value = u128_to_i128(open_interest_in_tokens * price);
+ let key = keys::claimed_collateral_amount_key(market_address, token, time_key, account);
+ data_store.set_u256(key, adjusted_claimable_amount);
- // Return the PNL.
- // If `is_long` is true, then the PNL is the difference between the current worth of all positions and the cost of all positions.
- // If `is_long` is false, then the PNL is the difference between the cost of all positions and the current worth of all positions.
- if is_long {
- open_interest_value - open_interest
+ let key = keys::claimable_collateral_amount_key(market_address, token);
+ let next_pool_value = data_store.decrement_u256(key, amount_to_be_claimed);
+
+ IBankDispatcher { contract_address: market_address }
+ .transfer_out(market_address, token, receiver, amount_to_be_claimed);
+
+ validate_market_token_balance_with_address(data_store, market_address);
+
+ event_emitter
+ .emit_collateral_claimed(
+ market_address,
+ token,
+ account,
+ receiver,
+ time_key,
+ amount_to_be_claimed,
+ next_pool_value
+ );
+
+ amount_to_be_claimed
+}
+
+
+/// Applies a delta to the pool amount for a given market and token.
+/// `validatePoolAmount` is not called in this function since `apply_delta_to_pool_amount`
+/// is typically called when receiving fees.
+/// # Arguments
+/// * `data_store` - Data store to manage internal states.
+/// * `event_emitter` - Emits events for the system.
+/// * `market` - The market to which the delta will be applied.
+/// * `token` - The token to which the delta will be applied.
+/// * `delta` - The delta amount to apply.
+fn apply_delta_to_pool_amount(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: Market,
+ token: ContractAddress,
+ delta: i256
+) -> u256 {
+ let key = keys::pool_amount_key(market.market_token, token);
+ let next_value = data_store.apply_delta_to_u256(key, delta, 'negative poolAmount');
+
+ apply_delta_to_virtual_inventory_for_swaps(data_store, event_emitter, market, token, delta);
+
+ event_emitter.emit_pool_amount_updated(market.market_token, token, delta, next_value);
+
+ next_value
+}
+
+fn get_adjusted_swap_impact_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_positive: bool
+) -> u256 {
+ let (positive_impact_factor, negative_impact_factor) = get_adjusted_swap_impact_factors(
+ data_store, market
+ );
+ if is_positive {
+ positive_impact_factor
} else {
- open_interest - open_interest_value
+ negative_impact_factor
+ }
+}
+
+fn get_adjusted_swap_impact_factors(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) -> (u256, u256) {
+ let mut positive_impact_factor = data_store
+ .get_u256(keys::swap_impact_factor_key(market, true));
+ let negative_impact_factor = data_store.get_u256(keys::swap_impact_factor_key(market, false));
+ // if the positive impact factor is more than the negative impact factor, positions could be opened
+ // and closed immediately for a profit if the difference is sufficient to cover the position fees
+ if positive_impact_factor > negative_impact_factor {
+ positive_impact_factor = negative_impact_factor;
+ }
+ (positive_impact_factor, negative_impact_factor)
+}
+
+fn get_adjusted_position_impact_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_positive: bool
+) -> u256 {
+ let (positive_impact_factor, negative_impact_factor) = get_adjusted_position_impact_factors(
+ data_store, market
+ );
+ if is_positive {
+ positive_impact_factor
+ } else {
+ negative_impact_factor
+ }
+}
+
+fn get_adjusted_position_impact_factors(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) -> (u256, u256) {
+ let mut positive_impact_factor = data_store
+ .get_u256(keys::position_impact_factor_key(market, true));
+ let negative_impact_factor = data_store
+ .get_u256(keys::position_impact_factor_key(market, false));
+ // if the positive impact factor is more than the negative impact factor, positions could be opened
+ // and closed immediately for a profit if the difference is sufficient to cover the position fees
+ if positive_impact_factor > negative_impact_factor {
+ positive_impact_factor = negative_impact_factor;
+ }
+ (positive_impact_factor, negative_impact_factor)
+}
+
+/// Cap the input priceImpactUsd by the available amount in the swap impact pool and the max positive swap impact factor.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The trading market.
+/// * `token_price` - The price of the token.
+/// * `price_impact_usd` - The calculated USD price impact.
+/// * `size_delta_usd` - The size delta in USD.
+/// # Returns
+/// The capped priceImpactUsd.
+fn get_capped_position_impact_usd(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ token_price: Price,
+ mut price_impact_usd: i256,
+ size_delta_usd: u256
+) -> i256 {
+ if price_impact_usd < Zeroable::zero() {
+ return price_impact_usd;
+ }
+
+ let impact_pool_amount = get_position_impact_pool_amount(data_store, market);
+ let max_price_impact_usd_based_on_impact_pool = calc::to_signed(
+ impact_pool_amount * token_price.min, true
+ );
+
+ if price_impact_usd > max_price_impact_usd_based_on_impact_pool {
+ price_impact_usd = max_price_impact_usd_based_on_impact_pool;
+ }
+
+ let max_price_impact_factor = get_max_position_impact_factor(data_store, market, true);
+ let max_price_impact_usd_based_on_max_price_impact_factor = calc::to_signed(
+ precision::apply_factor_u256(size_delta_usd, max_price_impact_factor), true
+ );
+
+ if price_impact_usd > max_price_impact_usd_based_on_max_price_impact_factor {
+ max_price_impact_usd_based_on_max_price_impact_factor
+ } else {
+ price_impact_usd
}
}
@@ -374,8 +811,8 @@ fn get_pnl(
/// The position impact pool amount.
fn get_position_impact_pool_amount(
data_store: IDataStoreDispatcher, market_address: ContractAddress
-) -> u128 {
- data_store.get_u128(keys::position_impact_pool_amount_key(market_address))
+) -> u256 {
+ data_store.get_u256(keys::position_impact_pool_amount_key(market_address))
}
/// Get the swap impact pool amount.
@@ -387,79 +824,61 @@ fn get_position_impact_pool_amount(
/// The swap impact pool amount.
fn get_swap_impact_pool_amount(
data_store: IDataStoreDispatcher, market_address: ContractAddress, token: ContractAddress
-) -> u128 {
- data_store.get_u128(keys::swap_impact_pool_amount_key(market_address, token))
+) -> u256 {
+ data_store.get_u256(keys::swap_impact_pool_amount_key(market_address, token))
}
-/// Apply delta to the position impact pool.
+/// Apply delta to the swap impact pool.
/// # Arguments
/// * `data_store` - The data store to use.
/// * `event_emitter` - The interface to interact with `EventEmitter` contract.
/// * `market_address` - The market to apply the delta to.
+/// * `token` - The token to apply the delta to.
/// * `delta` - The delta to apply.
/// # Returns
-/// The updated position impact pool amount.
-fn apply_delta_to_position_impact_pool(
+/// The updated swap impact pool amount.
+fn apply_delta_to_swap_impact_pool(
data_store: IDataStoreDispatcher,
event_emitter: IEventEmitterDispatcher,
market_address: ContractAddress,
- delta: u128
-) -> u128 {
- // Increment the position impact pool amount.
+ token: ContractAddress,
+ delta: i256
+) -> u256 {
+ // Increment the swap impact pool amount.
let next_value = data_store
- .increment_u128(keys::position_impact_pool_amount_key(market_address), delta);
+ .apply_bounded_delta_to_u256(
+ keys::swap_impact_pool_amount_key(market_address, token), delta
+ );
// Emit event.
- event_emitter.emit_position_impact_pool_amount_updated(market_address, delta, next_value);
+ event_emitter.emit_swap_impact_pool_amount_updated(market_address, token, delta, next_value);
- // Return the updated position impact pool amount.
+ // Return the updated swap impact pool amount.
next_value
}
-/// Applies a delta to the pool amount for a given market and token.
-/// `validatePoolAmount` is not called in this function since `apply_delta_to_pool_amount`
-/// is typically called when receiving fees.
-/// # Arguments
-/// * `data_store` - Data store to manage internal states.
-/// * `event_emitter` - Emits events for the system.
-/// * `market` - The market to which the delta will be applied.
-/// * `token` - The token to which the delta will be applied.
-/// * `delta` - The delta amount to apply.
-fn apply_delta_to_pool_amount(
- data_store: IDataStoreDispatcher,
- eventEmitter: IEventEmitterDispatcher,
- market: Market,
- token: ContractAddress,
- delta: u128 // This is supposed to be i128 when it will be supported.
-) -> u128 {
- //TODO
- 0
-}
-
-/// Apply delta to the swap impact pool.
+/// Apply delta to the position impact pool.
/// # Arguments
/// * `data_store` - The data store to use.
/// * `event_emitter` - The interface to interact with `EventEmitter` contract.
/// * `market_address` - The market to apply the delta to.
-/// * `token` - The token to apply the delta to.
/// * `delta` - The delta to apply.
/// # Returns
-/// The updated swap impact pool amount.
-fn apply_delta_to_swap_impact_pool(
+/// The updated position impact pool amount.
+fn apply_delta_to_position_impact_pool(
data_store: IDataStoreDispatcher,
event_emitter: IEventEmitterDispatcher,
market_address: ContractAddress,
- token: ContractAddress,
- delta: u128
-) -> u128 {
- // Increment the swap impact pool amount.
+ delta: i256
+) -> u256 {
+ // Increment the position impact pool amount.
let next_value = data_store
- .increment_u128(keys::swap_impact_pool_amount_key(market_address, token), delta);
+ .apply_bounded_delta_to_u256(keys::position_impact_pool_amount_key(market_address), delta);
// Emit event.
- event_emitter.emit_swap_impact_pool_amount_updated(market_address, token, delta, next_value);
+ event_emitter.emit_position_impact_pool_amount_updated(market_address, delta, next_value);
- // Return the updated swap impact pool amount.
+ // Return the updated position impact pool amount.
next_value
}
@@ -479,21 +898,16 @@ fn apply_delta_to_open_interest(
market: @Market,
collateral_token: ContractAddress,
is_long: bool,
- // TODO: Move to `i128` when `apply_delta_to_u128` is implemented and when supported in used Cairo version.
- delta: i128
-) -> u128 {
+ delta: i256
+) -> u256 {
// Check that the market is not a swap only market.
assert(
(*market.index_token).is_non_zero(),
MarketError::OPEN_INTEREST_CANNOT_BE_UPDATED_FOR_SWAP_ONLY_MARKET
);
-
// Increment the open interest by the delta.
- // TODO: create `apply_delta_to_u128` function in `DataStore` contract and pass `delta` as `i128`.
- let next_value = data_store
- .increment_u128(
- keys::open_interest_key(*market.market_token, collateral_token, is_long), 0
- );
+ let key = keys::open_interest_key(*market.market_token, collateral_token, is_long);
+ let next_value = data_store.apply_delta_to_u256(key, delta, 'negative open interest');
// If the open interest for longs is increased then tokens were virtually bought from the pool
// so the virtual inventory should be decreased.
@@ -504,566 +918,1968 @@ fn apply_delta_to_open_interest(
// If the open interest for shorts is decreased then tokens were virtually bought from the pool
// so the virtual inventory should be decreased.
- // We need to validate the open interest if the delta is positive.
- //if 0_i128 < delta {
- //validate_open_interest(data_store, market, is_long);
- //}
+ if is_long {
+ apply_delta_to_virtual_inventory_for_positions(
+ data_store, event_emitter, *market.index_token, i256_neg(delta)
+ );
+ } else {
+ apply_delta_to_virtual_inventory_for_positions(
+ data_store, event_emitter, *market.index_token, delta
+ );
+ }
- 0
-}
+ if (delta > Zeroable::zero()) {
+ validate_open_interest(data_store, market, is_long);
+ }
+ event_emitter
+ .emit_open_interest_updated(
+ *market.market_token, collateral_token, is_long, delta, next_value
+ );
-/// Validates the swap path to ensure each market in the path is valid and the path length does not
-// exceed the maximum allowed length.
-/// # Arguments
-/// * `data_store` - The DataStore contract containing platform configuration.
-/// * `swap_path` - A vector of market addresses forming the swap path.
-fn validate_swap_path(
- data_store: IDataStoreDispatcher, token_swap_path: Span32
-) { //TODO
+ next_value
}
-
-/// @dev update the swap impact pool amount, if it is a positive impact amount
-/// cap the impact amount to the amount available in the swap impact pool
+/// Apply a delta to the open interest in tokens.
/// # Arguments
-/// *`data_store` DataStore
-/// *`event_emitter` EventEmitter
-/// *`market` the market to apply to
-/// *`token` the token to apply to
-/// *`token_price` the price of the token
-/// *`price_impact_usd` the USD price impact
+/// * `data_store` - The data store to use.
+/// * `event_emitter` - The interface to interact with `EventEmitter` contract.
+/// * `market` - The market to apply the delta to.
+/// * `collateral_token` - The collateral token to apply the delta to.
+/// * `is_long` - Whether to apply the delta to the long or short side.
+/// * `delta` - The delta to apply.
/// # Returns
-/// The impact amount as integer
-fn apply_swap_impact_with_cap(
+/// The updated open interest in tokens.
+fn apply_delta_to_open_interest_in_tokens(
data_store: IDataStoreDispatcher,
event_emitter: IEventEmitterDispatcher,
- market: ContractAddress,
- token: ContractAddress,
- token_price: Price,
- price_impact_usd: i128
-) -> i128 {
- // TODO: implement
- return 0;
-}
+ market: Market,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ delta: i256
+) -> u256 {
+ let key = keys::open_interest_in_tokens_key(market.market_token, collateral_token, is_long);
+ let next_value = data_store.apply_delta_to_u256(key, delta, 'negative open interest tokens');
-/// @dev validate that the pool amount is within the max allowed amount
-/// # Arguments
-/// *`data_store` DataStore
-/// *`market` the market to check
-/// *`token` the token to check
-fn validate_pool_amount(
- data_store: @IDataStoreDispatcher, market: @Market, token: ContractAddress
-) { // TODO
+ event_emitter
+ .emit_open_interest_in_tokens_updated(
+ market.market_token, collateral_token, is_long, delta, next_value
+ );
+
+ next_value
}
-/// @dev validate that the amount of tokens required to be reserved
-/// is below the configured threshold
+/// @dev apply a delta to the collateral sum
/// # Arguments
/// * `data_store` DataStore
-/// * `market` the market values
-/// * `prices` the prices of the market tokens
-/// * `is_long` whether to check the long or short side
-fn validata_reserve(
- data_store: @IDataStoreDispatcher, market: @Market, prices: @MarketPrices, is_long: bool
-) { // TODO
+/// * `event_emitter` EventEmitter
+/// * `market` the market to apply to
+/// * `collateral_token` the collateralToken to apply to
+/// * `is_long` whether to apply to the long or short side
+/// * `delta` the delta amount
+/// # Returns
+/// The updated collateral sum amount
+fn apply_delta_to_collateral_sum(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ delta: i256
+) -> u256 {
+ let key = keys::collateral_sum_key(market, collateral_token, is_long);
+ let next_value = data_store.apply_delta_to_u256(key, delta, 'negative collateralSum');
+
+ event_emitter.emit_collateral_sum_updated(market, collateral_token, is_long, delta, next_value);
+
+ next_value
}
-/// Validata the open interest.
+/// Update the funding state
/// # Arguments
/// * `data_store` - The data store to use.
-/// * `market` - The market to validate the open interest for.
-/// * `is_long` - Whether to validate the long or short side.
-fn validate_open_interest(data_store: IDataStoreDispatcher, market: @Market, is_long: bool) {
- // Get the open interest.
- let open_interest = get_open_interest_for_market_is_long(data_store, market, is_long);
+/// * `event_emitter` - The event emitter.
+/// * `market` - The market.
+/// * `prices` - The market prices.
+fn update_funding_state(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: Market,
+ prices: MarketPrices
+) {
+ let result = get_next_funding_amount_per_size(data_store, market, prices);
+
+ apply_delta_to_funding_fee_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.long_token,
+ true,
+ result.funding_fee_amount_per_size_delta.long.long_token
+ );
- // Get the maximum open interest.
- let max_open_interest = get_max_open_interest(data_store, *market.market_token, is_long);
+ apply_delta_to_funding_fee_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.long_token,
+ false,
+ result.funding_fee_amount_per_size_delta.short.long_token
+ );
- // Check that the open interest is not greater than the maximum open interest.
- assert(open_interest <= max_open_interest, MarketError::MAX_OPEN_INTEREST_EXCEEDED);
-}
+ apply_delta_to_funding_fee_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.short_token,
+ true,
+ result.funding_fee_amount_per_size_delta.long.short_token
+ );
-/// Validata the swap market.
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market to validate the open interest for.
-fn validate_swap_market(data_store: @IDataStoreDispatcher, market: @Market) { // TODO
+ apply_delta_to_funding_fee_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.short_token,
+ false,
+ result.funding_fee_amount_per_size_delta.short.short_token
+ );
+
+ apply_delta_to_claimable_funding_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.long_token,
+ true,
+ result.claimable_funding_amount_per_size_delta.long.long_token
+ );
+
+ apply_delta_to_claimable_funding_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.long_token,
+ false,
+ result.claimable_funding_amount_per_size_delta.short.long_token
+ );
+
+ apply_delta_to_claimable_funding_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.short_token,
+ true,
+ result.claimable_funding_amount_per_size_delta.long.short_token
+ );
+
+ apply_delta_to_claimable_funding_amount_per_size(
+ data_store,
+ event_emitter,
+ market.market_token,
+ market.short_token,
+ false,
+ result.claimable_funding_amount_per_size_delta.short.short_token
+ );
+
+ let key = keys::funding_updated_at_key(market.market_token);
+ data_store.set_u256(key, get_block_timestamp().into());
}
-// @dev get the opposite token of the market
-// if the input_token is the token_long return the short_token and vice versa
+/// Get the next funding amount per size values.
/// # Arguments
-/// * `market` - The market to validate the open interest for.
-/// * `token` - The input_token.
+/// * `data_store` - The data store to use.
+/// * `market` - The market to update.
+/// * `prices` - The market prices.
/// # Returns
-/// The opposite token.
-fn get_opposite_token(market: @Market, token: ContractAddress) -> ContractAddress {
- // TODO
- token
-}
+/// The next funding amount per size values.
+fn get_next_funding_amount_per_size(
+ data_store: IDataStoreDispatcher, market: Market, prices: MarketPrices
+) -> GetNextFundingAmountPerSizeResult {
+ let mut result: GetNextFundingAmountPerSizeResult = Default::default();
+ let divisor = get_pool_divisor(market.long_token, market.short_token);
+
+ // get the open interest values by long / short and by collateral used.
+
+ let open_interest = PositionType {
+ long: CollateralType {
+ long_token: get_open_interest_div(
+ data_store, market.market_token, market.long_token, true, divisor
+ ),
+ short_token: get_open_interest_div(
+ data_store, market.market_token, market.short_token, true, divisor
+ ),
+ },
+ short: CollateralType {
+ long_token: get_open_interest_div(
+ data_store, market.market_token, market.long_token, false, divisor
+ ),
+ short_token: get_open_interest_div(
+ data_store, market.market_token, market.short_token, false, divisor
+ ),
+ },
+ };
-// Get the min pnl factor after ADL
-// Parameters
-// * `data_store` - - The data store to use.
-// * `market` - the market to check.
-// * `is_long` whether to check the long or short side.
-fn get_min_pnl_factor_after_adl(
- data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
-) -> u128 {
- // TODO
- 0
-}
+ // sum the open interest values to get the total long and short open interest values.
+ let long_open_interest = open_interest.long.long_token + open_interest.long.short_token;
+ let short_open_interest = open_interest.short.long_token + open_interest.short.short_token;
-// Get the ratio of pnl to pool value.
-// # Arguments
-// * `data_store` - The data_store dispatcher.
-// * `market` the market values.
-// * `prices` the prices of the market tokens.
-// * `is_long` whether to get the value for the long or short side.
-// * `maximize` whether to maximize the factor.
-// # Returns
-// (pnl of positions) / (long or short pool value)
-fn get_pnl_to_pool_factor(
+ // if either long or short open interest is zero, then funding should not be updated
+ // as there would not be any user to pay the funding to.
+ if long_open_interest == 0 || short_open_interest == 0 {
+ return result;
+ }
+
+ // if the blockchain is not progressing / a market is disabled, funding fees
+ // will continue to accumulate
+ // this should be a rare occurrence so funding fees are not adjusted for this case.
+ let duration_in_seconds = get_seconds_since_funding_updated(data_store, market.market_token);
+
+ let diff_usd = calc::diff(long_open_interest, short_open_interest);
+ let total_open_interest = long_open_interest + short_open_interest;
+ let size_of_larger_side = if long_open_interest > short_open_interest {
+ long_open_interest
+ } else {
+ short_open_interest
+ };
+
+ result
+ .funding_factor_per_second =
+ get_funding_factor_per_second(
+ data_store, market.market_token, diff_usd, total_open_interest
+ );
+
+ // for single token markets, if there is $200,000 long open interest
+ // and $100,000 short open interest and if the fundingUsd is $8:
+ // fundingUsdForLongCollateral: $4
+ // fundingUsdForShortCollateral: $4
+ // fundingFeeAmountPerSizeDelta.long.longToken: 4 / 100,000
+ // fundingFeeAmountPerSizeDelta.long.shortToken: 4 / 100,000
+ // claimableFundingAmountPerSizeDelta.short.longToken: 4 / 100,000
+ // claimableFundingAmountPerSizeDelta.short.shortToken: 4 / 100,000
+ //
+ // the divisor for fundingFeeAmountPerSizeDelta is 100,000 because the
+ // cache.openInterest.long.longOpenInterest and cache.openInterest.long.shortOpenInterest is divided by 2
+ //
+ // when the fundingFeeAmountPerSize value is incremented, it would be incremented twice:
+ // 4 / 100,000 + 4 / 100,000 = 8 / 100,000
+ //
+ // since the actual long open interest is $200,000, this would result in a total of 8 / 100,000 * 200,000 = $16 being charged
+ //
+ // when the claimableFundingAmountPerSize value is incremented, it would similarly be incremented twice:
+ // 4 / 100,000 + 4 / 100,000 = 8 / 100,000
+ //
+ // when calculating the amount to be claimed, the longTokenClaimableFundingAmountPerSize and shortTokenClaimableFundingAmountPerSize
+ // are compared against the market's claimableFundingAmountPerSize for the longToken and claimableFundingAmountPerSize for the shortToken
+ //
+ // since both these values will be duplicated, the amount claimable would be:
+ // (8 / 100,000 + 8 / 100,000) * 100,000 = $16
+ //
+ // due to these, the fundingUsd should be divided by the divisor
+
+ let funding_usd = precision::apply_factor_u256(
+ size_of_larger_side, duration_in_seconds * result.funding_factor_per_second
+ );
+ let funding_usd = funding_usd / divisor;
+
+ result.longs_pay_shorts = long_open_interest > short_open_interest;
+
+ // split the fundingUsd value by long and short collateral
+ // e.g. if the fundingUsd value is $500, and there is $1000 of long open interest using long collateral and $4000 of long open interest
+ // with short collateral, then $100 of funding fees should be paid from long positions using long collateral, $400 of funding fees
+ // should be paid from long positions using short collateral
+ // short positions should receive $100 of funding fees in long collateral and $400 of funding fees in short collateral
+ let funding_usd_for_long_collateral = if result.longs_pay_shorts {
+ precision::mul_div(funding_usd, open_interest.long.long_token, long_open_interest)
+ } else {
+ precision::mul_div(funding_usd, open_interest.short.long_token, short_open_interest)
+ };
+
+ let funding_usd_for_short_collateral = if result.longs_pay_shorts {
+ precision::mul_div(funding_usd, open_interest.long.short_token, long_open_interest)
+ } else {
+ precision::mul_div(funding_usd, open_interest.short.short_token, short_open_interest)
+ };
+
+ // calculate the change in funding amount per size values
+ // for example, if the fundingUsdForLongCollateral is $100, the longToken price is $2000, the longOpenInterest is $10,000, shortOpenInterest is $5000
+ // if longs pay shorts then the fundingFeeAmountPerSize.long.longToken should be increased by 0.05 tokens per $10,000 or 0.000005 tokens per $1
+ // the claimableFundingAmountPerSize.short.longToken should be increased by 0.05 tokens per $5000 or 0.00001 tokens per $1
+ if result.longs_pay_shorts {
+ // use the same longTokenPrice.max and shortTokenPrice.max to calculate the amount to be paid and received
+ // positions only pay funding in the position's collateral token
+ // so the fundingUsdForLongCollateral is divided by the total long open interest for long positions using the longToken as collateral
+ // and the fundingUsdForShortCollateral is divided by the total long open interest for long positions using the shortToken as collateral
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_long_collateral,
+ open_interest.long.long_token,
+ prices.long_token_price.max,
+ true // roundUpMagnitude
+ );
+ result.funding_fee_amount_per_size_delta.long.long_token = amount;
+
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_short_collateral,
+ open_interest.long.short_token,
+ prices.short_token_price.max,
+ true // roundUpMagnitude
+ );
+ result.funding_fee_amount_per_size_delta.long.short_token = amount;
+
+ // positions receive funding in both the longToken and shortToken
+ // so the fundingUsdForLongCollateral and fundingUsdForShortCollateral is divided by the total short open interest
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_long_collateral,
+ short_open_interest,
+ prices.long_token_price.max,
+ false // roundUpMagnitude
+ );
+ result.claimable_funding_amount_per_size_delta.short.long_token = amount;
+
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_short_collateral,
+ short_open_interest,
+ prices.short_token_price.max,
+ false // roundUpMagnitude
+ );
+ result.claimable_funding_amount_per_size_delta.short.short_token = amount;
+ } else {
+ // use the same longTokenPrice.max and shortTokenPrice.max to calculate the amount to be paid and received
+ // positions only pay funding in the position's collateral token
+ // so the fundingUsdForLongCollateral is divided by the total short open interest for short positions using the longToken as collateral
+ // and the fundingUsdForShortCollateral is divided by the total short open interest for short positions using the shortToken as collateral
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_long_collateral,
+ open_interest.short.long_token,
+ prices.long_token_price.max,
+ true // roundUpMagnitude
+ );
+ result.funding_fee_amount_per_size_delta.short.long_token = amount;
+
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_short_collateral,
+ open_interest.short.short_token,
+ prices.short_token_price.max,
+ true // roundUpMagnitude
+ );
+ result.funding_fee_amount_per_size_delta.short.short_token = amount;
+
+ // positions receive funding in both the longToken and shortToken
+ // so the fundingUsdForLongCollateral and fundingUsdForShortCollateral is divided by the total long open interest
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_long_collateral,
+ long_open_interest,
+ prices.long_token_price.max,
+ false // roundUpMagnitude
+ );
+ result.claimable_funding_amount_per_size_delta.long.long_token = amount;
+
+ let amount = get_funding_amount_per_size_delta(
+ funding_usd_for_short_collateral,
+ long_open_interest,
+ prices.short_token_price.max,
+ false // roundUpMagnitude
+ );
+ result.claimable_funding_amount_per_size_delta.long.short_token = amount;
+ }
+
+ result
+}
+
+fn get_swap_impact_amount_with_cap(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ token: ContractAddress,
+ token_price: Price,
+ price_impact_usd: i256
+) -> i256 {
+ let mut impact_amount: i256 = Zeroable::zero();
+ // positive impact: minimize impactAmount, use tokenPrice.max
+ // negative impact: maximize impactAmount, use tokenPrice.min
+ if price_impact_usd > Zeroable::zero() {
+ // round positive impactAmount down, this will be deducted from the swap impact pool for the user
+ let price = to_signed(token_price.max, true);
+
+ let max_impact_amount = to_signed(
+ get_swap_impact_pool_amount(data_store, market, token), true
+ );
+
+ if (impact_amount > max_impact_amount) {
+ impact_amount = max_impact_amount;
+ }
+ } else {
+ let price = token_price.min;
+ // round negative impactAmount up, this will be deducted from the user
+ impact_amount = roundup_magnitude_division(price_impact_usd, price);
+ }
+ impact_amount
+}
+
+fn get_open_interest_div(
data_store: IDataStoreDispatcher,
- oracle: IOracleDispatcher,
market: ContractAddress,
+ collateral_token: ContractAddress,
is_long: bool,
- maximize: bool
-) -> u128 {
- // TODO
- 0
+ divisor: u256
+) -> u256 {
+ error_utils::check_division_by_zero(divisor, 'get_open_interest');
+ let key = keys::open_interest_key(market, collateral_token, is_long);
+ data_store.get_u256(key) / divisor
+}
+
+/// Get the long and short open interest for a market.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to get the open interest for.
+/// # Returns
+/// The long and short open interest for a market.
+fn get_open_interest_for_market(data_store: IDataStoreDispatcher, market: @Market) -> u256 {
+ // Get the open interest for the long token as collateral.
+ let long_open_interest = get_open_interest_for_market_is_long(data_store, market, true);
+ // Get the open interest for the short token as collateral.
+ let short_open_interest = get_open_interest_for_market_is_long(data_store, market, false);
+ long_open_interest + short_open_interest
+}
+
+/// Get the long and short open interest for a market.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to get the open interest for.
+/// * `is_long` - Whether to get the long or short open interest.
+/// # Returns
+/// The long and short open interest for a market.
+fn get_open_interest_for_market_is_long(
+ data_store: IDataStoreDispatcher, market: @Market, is_long: bool
+) -> u256 {
+ // Get the pool divisor.
+ let divisor = get_pool_divisor(*market.long_token, *market.short_token);
+ // Get the open interest for the long token as collateral.
+ let open_interest_using_long_token_as_collateral = get_open_interest_div(
+ data_store, *market.market_token, *market.long_token, is_long, divisor
+ );
+ // Get the open interest for the short token as collateral.
+ let open_interest_using_short_token_as_collateral = get_open_interest_div(
+ data_store, *market.market_token, *market.short_token, is_long, divisor
+ );
+ // Return the sum of the open interests.
+ open_interest_using_long_token_as_collateral + open_interest_using_short_token_as_collateral
+}
+
+
+/// Get the long and short open interest in tokens for a market.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to get the open interest for.
+/// * `is_long` - Whether to get the long or short open interest.
+/// # Returns
+/// The long and short open interest in tokens for a market based on the collateral token used.
+fn get_open_interest_in_tokens_for_market(
+ data_store: IDataStoreDispatcher, market: @Market, is_long: bool,
+) -> u256 {
+ // Get the pool divisor.
+ let divisor = get_pool_divisor(*market.long_token, *market.short_token);
+
+ // Get the open interest for the long token as collateral.
+ let open_interest_using_long_token_as_collateral = get_open_interest_in_tokens(
+ data_store, *market.market_token, *market.long_token, is_long, divisor
+ );
+ // Get the open interest for the short token as collateral.
+ let open_interest_using_short_token_as_collateral = get_open_interest_in_tokens(
+ data_store, *market.market_token, *market.short_token, is_long, divisor
+ );
+ // Return the sum of the open interests.
+ open_interest_using_long_token_as_collateral + open_interest_using_short_token_as_collateral
+}
+
+/// Get the long and short open interest in tokens for a market based on the collateral token used.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to get the open interest for.
+/// * `collateral_token` - The collateral token to check.
+/// * `is_long` - Whether to get the long or short open interest.
+/// * `divisor` - The divisor to use for the open interest.
+/// # Returns
+/// The long and short open interest in tokens for a market based on the collateral token used.
+fn get_open_interest_in_tokens(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ divisor: u256
+) -> u256 {
+ error_utils::check_division_by_zero(divisor, 'get_open_interest_in_tokens');
+ data_store.get_u256(keys::open_interest_in_tokens_key(market, collateral_token, is_long))
+ / divisor
+}
+
+/// Get the pool divisor.
+/// This is used to divide the values of `get_pool_amount` and `get_open_interest`
+/// if the longToken and shortToken are the same, then these values have to be divided by two
+/// to avoid double counting
+/// # Arguments
+/// * `long_token` - The long token.
+/// * `short_token` - The short token.
+/// # Returns
+/// The pool divisor.
+fn get_pool_divisor(long_token: ContractAddress, short_token: ContractAddress) -> u256 {
+ if long_token == short_token {
+ 2
+ } else {
+ 1
+ }
+}
+
+/// Update the swap impact pool amount, if it is a positive impact amount
+/// cap the impact amount to the amount available in the swap impact pool
+/// # Arguments
+/// *`data_store` DataStore
+/// *`event_emitter` EventEmitter
+/// *`market` the market to apply to
+/// *`token` the token to apply to
+/// *`token_price` the price of the token
+/// *`price_impact_usd` the USD price impact
+/// # Returns
+/// The impact amount as integer
+fn apply_swap_impact_with_cap(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ token: ContractAddress,
+ token_price: Price,
+ price_impact_usd: i256
+) -> i256 {
+ let impact_amount: i256 = get_swap_impact_amount_with_cap(
+ data_store, market, token, token_price, price_impact_usd
+ );
+
+ // if there is a positive impact, the impact pool amount should be reduced
+ // if there is a negative impact, the impact pool amount should be increased
+ apply_delta_to_swap_impact_pool(
+ data_store, event_emitter, market, token, i256_neg(impact_amount)
+ );
+
+ return impact_amount;
+}
+
+/// @dev validate that the pool amount is within the max allowed amount
+/// # Arguments
+/// *`data_store` DataStore
+/// *`market` the market to check
+/// *`token` the token to check
+fn validate_pool_amount(
+ data_store: @IDataStoreDispatcher, market: @Market, token: ContractAddress
+) {
+ let pool_amount: u256 = get_pool_amount(*data_store, market, token);
+ let max_pool_amount: u256 = get_max_pool_amount(*data_store, *market.market_token, token);
+ if (pool_amount > max_pool_amount) {
+ MarketError::MAX_POOL_AMOUNT_EXCEEDED(pool_amount, max_pool_amount);
+ }
+}
+
+use debug::PrintTrait;
+
+/// Validates that the amount of tokens required to be reserved is below the configured threshold.
+/// # Arguments
+/// * `dataStore`: DataStore - The data storage instance.
+/// * `market`: Market values to consider.
+/// * `prices`: Prices of the market tokens.
+/// * `is_long`: A boolean flag to indicate whether to check the long or short side.
+fn validate_reserve(
+ data_store: IDataStoreDispatcher, market: @Market, prices: @MarketPrices, is_long: bool
+) {
+ // poolUsd is used instead of pool amount as the indexToken may not match the longToken
+ // additionally, the shortToken may not be a stablecoin
+ let pool_usd = get_pool_usd_without_pnl(data_store, market, prices, is_long, false);
+ let reserve_factor = get_reserve_factor(data_store, *market.market_token, is_long);
+ let max_reserved_usd = apply_factor_u256(pool_usd, reserve_factor);
+
+ let reserved_usd = get_reserved_usd(data_store, market, prices, is_long);
+
+ if (reserved_usd > max_reserved_usd) {
+ MarketError::INSUFFICIENT_RESERVE(reserved_usd, max_reserved_usd);
+ }
+}
+
+
+/// Validate the open interest.
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market to validate the open interest for.
+/// * `is_long` - Whether to validate the long or short side.
+fn validate_open_interest(data_store: IDataStoreDispatcher, market: @Market, is_long: bool) {
+ // Get the open interest.
+ let open_interest = get_open_interest_for_market_is_long(data_store, market, is_long);
+ // Get the maximum open interest.
+ let max_open_interest = get_max_open_interest(data_store, *market.market_token, is_long);
+
+ // Check that the open interest is not greater than the maximum open interest.
+ if (open_interest > max_open_interest) {
+ MarketError::MAX_OPEN_INTEREST_EXCEDEED(open_interest, max_open_interest);
+ }
}
// Get the ratio of pnl to pool value.
// # Arguments
// * `data_store` - The data_store dispatcher.
-// * `market` Rhe market.
+// * `market` the market values.
// * `prices` the prices of the market tokens.
// * `is_long` whether to get the value for the long or short side.
// * `maximize` whether to maximize the factor.
// # Returns
// (pnl of positions) / (long or short pool value)
-// TODO same function names getPnlToPoolFactor
-fn get_pnl_to_pool_factor_from_prices(
+fn get_pnl_to_pool_factor(
data_store: IDataStoreDispatcher,
- market: Market,
- prices: MarketPrices,
+ oracle: IOracleDispatcher,
+ market: ContractAddress,
is_long: bool,
maximize: bool
-) -> i128 {
- // TODO
- 0
-}
+) -> i256 {
+ let market: Market = get_enabled_market(data_store, market);
+ let prices: MarketPrices = MarketPrices {
+ index_token_price: oracle.get_primary_price(market.index_token),
+ long_token_price: oracle.get_primary_price(market.long_token),
+ short_token_price: oracle.get_primary_price(market.short_token)
+ };
+ return get_pnl_to_pool_factor_from_prices(data_store, @market, @prices, is_long, maximize);
+}
-// Check if the pending pnl exceeds the allowed amount
-// # Arguments
-// * `data_store` - The data_store dispatcher.
-// * `oracle` - The oracle dispatcher.
-// * `market` - The market to check.
-// * `prices` - The prices of the market tokens.
-// * `is_long` - Whether to check the long or short side.
-// * `pnl_factor_type` - The pnl factor type to check.
-fn is_pnl_factor_exceeded(
+/// Get the ratio of PNL (Profit and Loss) to pool value.
+/// # Arguments
+/// * `dataStore`: DataStore - The data storage instance.
+/// * `market`: Market values.
+/// * `prices`: Prices of the market tokens.
+/// * `isLong`: Whether to get the value for the long or short side.
+/// * `maximize`: Whether to maximize the factor.
+/// # Returns
+/// Returns the ratio of PNL of positions to long or short pool value.
+fn get_pnl_to_pool_factor_from_prices(
data_store: IDataStoreDispatcher,
- oracle: IOracleDispatcher,
- market_address: ContractAddress,
+ market: @Market,
+ prices: @MarketPrices,
is_long: bool,
- pnl_factor_type: felt252
-) -> (bool, u128, u128) {
- // TODO
- (true, 0, 0)
+ maximize: bool
+) -> i256 {
+ let pool_usd: u256 = get_pool_usd_without_pnl(data_store, market, prices, is_long, !maximize);
+ if pool_usd == 0 {
+ return Zeroable::zero();
+ }
+ let pnl: i256 = get_pnl(data_store, market, prices.index_token_price, is_long, maximize);
+ return to_factor_ival(pnl, pool_usd);
}
-// Check if the pending pnl exceeds the allowed amount
-// # Arguments
-// * `data_store` - The data_store dispatcher.
-// * `market` - The market to check.
-// * `prices` - The prices of the market tokens.
-// * `is_long` - Whether to check the long or short side.
-// * `pnl_factor_type` - The pnl factor type to check.
-fn is_pnl_factor_exceeded_direct(
+/// Validates the token balance for a single market.
+/// # Arguments
+/// * `data_store` - The data_store dispatcher
+/// * `market` - Address of the market to check.
+fn validate_market_token_balance_with_address(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) {
+ let enabled_market: Market = get_enabled_market(data_store, market);
+ validate_market_token_balance_check(data_store, enabled_market);
+}
+
+/// Update the cumulative borrowing factor for a market
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `event_emitter` - The event emitter.
+/// * `market` - The market.
+/// * `prices` - The market prices.
+/// * `is_long` - Whether to update the long or short side.
+fn update_cumulative_borrowing_factor(
data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
market: Market,
prices: MarketPrices,
- is_long: bool,
- pnl_factor_type: felt252
-) -> (bool, i128, u128) {
- // TODO
- (true, 0, 0)
+ is_long: bool
+) {
+ let (_, delta) = get_next_cumulative_borrowing_factor(data_store, market, prices, is_long);
+ increment_cumulative_borrowing_factor(
+ data_store, event_emitter, market.market_token, is_long, delta
+ );
+ let block_timestamp: u256 = starknet::info::get_block_timestamp().into();
+
+ data_store
+ .set_u256(
+ keys::cumulative_borrowing_factor_updated_at_key(market.market_token, is_long),
+ block_timestamp
+ );
+}
+
+/// Get the virtual inventory for positions.
+///
+/// # Arguments
+/// * `dataStore`: DataStore - The data storage instance.
+/// * `token`: The token to check.
+///
+/// # Returns
+/// Returns a tuple (has_virtual_inventory, virtual_token_inventory).
+fn get_virtual_inventory_for_positions(
+ data_store: IDataStoreDispatcher, token: ContractAddress
+) -> (bool, i256) {
+ let virtual_token_id: felt252 = data_store.get_felt252(keys::virtual_token_id_key(token));
+ if virtual_token_id == 0.into() {
+ return (false, Zeroable::zero());
+ }
+ return (true, data_store.get_i256(keys::virtual_inventory_for_positions_key(virtual_token_id)));
+}
+
+// store funding values as token amount per (Precision.FLOAT_PRECISION_SQRT / Precision.FLOAT_PRECISION) of USD size
+fn get_funding_amount_per_size_delta(
+ funding_usd: u256, open_interest: u256, token_price: u256, roundup_magnitude: bool
+) -> u256 {
+ if funding_usd == 0 || open_interest == 0 {
+ return 0;
+ }
+ let funding_usd_per_size: u256 = mul_div_roundup(
+ funding_usd, FLOAT_PRECISION * FLOAT_PRECISION_SQRT, open_interest, roundup_magnitude
+ );
+ if roundup_magnitude {
+ roundup_division(funding_usd_per_size, token_price)
+ } else {
+ funding_usd_per_size / token_price
+ }
+}
+
+// @dev validate that the amount of tokens required to be reserved for open interest
+// is below the configured threshold
+// @param dataStore: DataStore - The data storage instance.
+// @param market: Market values to consider.
+// @param prices: Prices of the market tokens.
+// @param is_long: A boolean flag to indicate whether to check the long or short side.
+fn validate_open_interest_reserve(
+ data_store: IDataStoreDispatcher, market: @Market, prices: @MarketPrices, is_long: bool
+) {
+ // poolUsd is used instead of pool amount as the indexToken may not match the longToken
+ // additionally, the shortToken may not be a stablecoin
+ let pool_usd: u256 = get_pool_usd_without_pnl(data_store, market, prices, is_long, false);
+ let reserve_factor: u256 = get_open_interest_reserve_factor(
+ data_store, *market.market_token, is_long
+ );
+ let max_reserved_usd: u256 = apply_factor_u256(pool_usd, reserve_factor);
+
+ let reserved_usd: u256 = get_reserved_usd(data_store, market, prices, is_long);
+
+ if (reserved_usd > max_reserved_usd) {
+ MarketError::INSUFFICIENT_RESERVE(reserved_usd, max_reserved_usd);
+ }
+}
+
+// @notice Get the next borrowing fees for a position.
+//
+// @param data_store IDataStoreDispatcher
+// @param position Position
+// @param market Market
+// @param prices @MarketPrices
+//
+// @return The next borrowing fees for a position.
+fn get_next_borrowing_fees(
+ data_store: IDataStoreDispatcher, position: @Position, market: @Market, prices: @MarketPrices
+) -> u256 {
+ let (next_cumulative_borrowing_factor, _) = get_next_cumulative_borrowing_factor(
+ data_store, *market, *prices, *position.is_long
+ );
+ if (next_cumulative_borrowing_factor < *position.borrowing_factor) {
+ MarketError::UNEXCEPTED_BORROWING_FACTOR(
+ *position.borrowing_factor, next_cumulative_borrowing_factor
+ );
+ }
+ let diff_factor = next_cumulative_borrowing_factor - *position.borrowing_factor;
+ return apply_factor_u256(*position.size_in_usd, diff_factor);
+}
+
+// @notice Get the total reserved USD required for positions.
+//
+// @param market The market to check.
+// @param prices The prices of the market tokens.
+// @param is_long Whether to get the value for the long or short side.
+//
+// @return The total reserved USD required for positions.
+fn get_reserved_usd(
+ data_store: IDataStoreDispatcher, market: @Market, prices: @MarketPrices, is_long: bool
+) -> u256 {
+ let mut reserved_usd: u256 = 0;
+ if (is_long) {
+ // for longs calculate the reserved USD based on the open interest and current indexTokenPrice
+ // this works well for e.g. an ETH / USD market with long collateral token as WETH
+ // the available amount to be reserved would scale with the price of ETH
+ // this also works for e.g. a SOL / USD market with long collateral token as WETH
+ // if the price of SOL increases more than the price of ETH, additional amounts would be
+ // automatically reserved
+ let open_interest_in_tokens = get_open_interest_in_tokens_for_market(
+ data_store, market, is_long
+ );
+ reserved_usd = open_interest_in_tokens * *prices.index_token_price.max;
+ } else {
+ // for shorts use the open interest as the reserved USD value
+ // this works well for e.g. an ETH / USD market with short collateral token as USDC
+ // the available amount to be reserved would not change with the price of ETH
+ reserved_usd = get_open_interest_for_market_is_long(data_store, market, is_long);
+ }
+ reserved_usd
+}
+
+fn get_is_long_token(market: Market, token: ContractAddress) -> bool {
+ if (token != market.long_token && token != market.short_token) {
+ MarketError::UNEXCEPTED_TOKEN(token);
+ }
+ return token == market.long_token;
+}
+
+/// Update the virtual inventory for swaps.
+///
+/// # Arguments
+/// * `data_store`: The data storage instance.
+/// * `market_address`: The address of the market to update.
+/// * `token`: The token to update.
+/// * `delta`: The update amount.
+///
+/// # Returns
+/// Returns a tuple (success, updated_amount).
+fn apply_delta_to_virtual_inventory_for_swaps(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: Market,
+ token: ContractAddress,
+ delta: i256
+) -> (bool, u256) {
+ let virtual_market_id: felt252 = data_store
+ .get_felt252(keys::virtual_market_id_key(market.market_token));
+ if (virtual_market_id == 0) {
+ return (false, 0);
+ }
+ let is_long_token: bool = get_is_long_token(market, token);
+
+ let next_value: u256 = data_store
+ .apply_bounded_delta_to_u256(
+ keys::virtual_inventory_for_swaps_key(virtual_market_id, is_long_token), delta
+ );
+
+ event_emitter
+ .emit_virtual_swap_inventory_updated(
+ market.market_token, is_long_token, virtual_market_id, delta, next_value
+ );
+
+ return (true, next_value);
+}
+
+/// Update the virtual inventory for positions.
+///
+/// # Arguments
+/// * `data_store`: The data storage instance.
+/// * `event_emitter`: The event emitter instance.
+/// * `token`: The token to update.
+/// * `delta`: The update amount.
+fn apply_delta_to_virtual_inventory_for_positions(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ token: ContractAddress,
+ delta: i256
+) -> (bool, i256) {
+ let virtual_token_id: felt252 = data_store.get_felt252(keys::virtual_token_id_key(token));
+ if (virtual_token_id == 0) {
+ return (false, Zeroable::zero());
+ }
+
+ let next_value: i256 = data_store
+ .apply_delta_to_i256(keys::virtual_inventory_for_positions_key(virtual_token_id), delta);
+ event_emitter
+ .emit_virtual_position_inventory_updated(token, virtual_token_id, delta, next_value);
+
+ return (true, next_value);
+}
+
+/// Get the borrowing fees for a position, assumes that cumulativeBorrowingFactor
+/// has already been updated to the latest value
+/// # Arguments
+/// * `dataStore` - DataStore
+/// * `position` - Position
+/// * `dataStore` - DataStore
+/// # Returns
+/// The borrowing fees for a position
+fn get_borrowing_fees(data_store: IDataStoreDispatcher, position: @Position) -> u256 {
+ let cumulative_borrowing_factor: u256 = get_cumulative_borrowing_factor(
+ @data_store, *position.market, *position.is_long
+ );
+
+ if (cumulative_borrowing_factor < *position.borrowing_factor) {
+ MarketError::UNEXCEPTED_BORROWING_FACTOR(
+ *position.borrowing_factor, cumulative_borrowing_factor
+ );
+ }
+ let diff_factor: u256 = cumulative_borrowing_factor - *position.borrowing_factor;
+ return apply_factor_u256(*position.size_in_usd, diff_factor);
+}
+
+/// Get the funding amount to be deducted or distributed
+/// # Arguments
+/// * `latestFundingAmountPerSize` - the latest funding amount per size
+/// * `dataSpositionFundingAmountPerSizetore` - the funding amount per size for the position
+/// * `positionSizeInUsd` - the position size in USD
+/// * `roundUpMagnitude` - whether the round up the result
+/// # Returns
+/// fundingAmount
+fn get_funding_amount(
+ latest_funding_amount_per_size: u256,
+ position_funding_amount_per_size: u256,
+ position_size_in_usd: u256,
+ roundup_magnitude: bool
+) -> u256 {
+ let funding_diff_factor: u256 = latest_funding_amount_per_size
+ - position_funding_amount_per_size;
+ return mul_div_roundup(
+ position_size_in_usd,
+ funding_diff_factor,
+ FLOAT_PRECISION * FLOAT_PRECISION_SQRT,
+ roundup_magnitude
+ );
+}
+
+/// The sum of open interest and pnl for a market
+// get_open_interest_in_tokens * token_price would not reflect pending positive pnl
+// for short positions, so get_open_interest_with_pnl should be used if that info is needed
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market.
+/// * `index_token_price` - The price of the index token.
+/// * `is_long` - Whether to check the long or short side
+/// * `maximize` - Whether to maximize or minimize the net PNL.
+/// # Returns
+/// The net pending pnl for a market
+fn get_open_interest_with_pnl(
+ data_store: IDataStoreDispatcher,
+ market: @Market,
+ index_token_price: @Price,
+ is_long: bool,
+ maximize: bool
+) -> i256 {
+ let open_interest: u256 = get_open_interest_for_market_is_long(data_store, market, is_long);
+ let pnl: i256 = get_pnl(data_store, market, index_token_price, is_long, maximize);
+ return sum_return_int_256(open_interest, pnl);
+}
+
+
+/// Get the virtual inventory for swaps
+/// # Arguments
+/// * `data_store` - The data store to use.
+/// * `market` - The market.
+/// # Returns
+/// The tuple (has virtual inventory, virtual long token inventory, virtual short token inventory)
+fn get_virtual_inventory_for_swaps(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) -> (bool, u256, u256) {
+ let virtual_market_id = data_store.get_felt252(keys::virtual_market_id_key(market));
+ if virtual_market_id.is_zero() {
+ return (false, 0, 0);
+ }
+
+ return (
+ true,
+ data_store.get_u256(keys::virtual_inventory_for_swaps_key(virtual_market_id, true)),
+ data_store.get_u256(keys::virtual_inventory_for_swaps_key(virtual_market_id, false))
+ );
+}
+
+fn apply_delta_to_funding_fee_amount_per_size(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ delta: u256
+) {
+ if delta == 0 {
+ return;
+ }
+ let delta = to_signed(delta, true);
+ let next_value: u256 = data_store
+ .apply_delta_to_u256(
+ keys::funding_fee_amount_per_size_key(market, collateral_token, is_long),
+ delta,
+ 'negative_funding_fee'
+ );
+ let delta = to_unsigned(delta);
+ event_emitter
+ .emit_funding_fee_amount_per_size_updated(
+ market, collateral_token, is_long, delta, next_value
+ );
+}
+
+// Get the max position impact factor
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_positive` - whether to check the positive or negative side
+// # Returns
+// The max position impact factor
+fn get_max_position_impact_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_positive: bool,
+) -> u256 {
+ let (max_positive_impact_factor, max_negative_impact_factor) = get_max_position_impact_factors(
+ data_store, market
+ );
+
+ if is_positive {
+ max_positive_impact_factor
+ } else {
+ max_negative_impact_factor
+ }
+}
+
+fn get_max_position_impact_factors(
+ data_store: IDataStoreDispatcher, market: ContractAddress,
+) -> (u256, u256) {
+ let mut max_positive_impact_factor: u256 = data_store
+ .get_u256(keys::max_position_impact_factor_key(market, true));
+ let max_negative_impact_factor: u256 = data_store
+ .get_u256(keys::max_position_impact_factor_key(market, false));
+
+ if max_positive_impact_factor > max_negative_impact_factor {
+ max_positive_impact_factor = max_negative_impact_factor;
+ }
+
+ (max_positive_impact_factor, max_negative_impact_factor)
+}
+
+// Get the max position impact factor for liquidations
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// # Returns
+// The max position impact factor for liquidations
+fn get_max_position_impact_factor_for_liquidations(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) -> u256 {
+ data_store.get_u256(keys::max_position_impact_factor_for_liquidations_key(market))
+}
+
+// Get the min collateral factor
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// # Returns
+// The min collateral factor
+fn get_min_collateral_factor(data_store: IDataStoreDispatcher, market: ContractAddress) -> u256 {
+ data_store.get_u256(keys::min_collateral_factor_key(market))
+}
+
+// Get the min collateral factor for open interest multiplier
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// The min collateral factor for open interest multiplier
+fn get_min_collateral_factor_for_open_interest_multiplier(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store
+ .get_u256(keys::min_collateral_factor_for_open_interest_multiplier_key(market, is_long))
+}
+
+// Get the min collateral factor for open interest
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `open_interest_delta` - the delta in open interest
+// `is_long` - whether to check the long or short side
+// # Returns
+// The min collateral factor for open interest
+fn get_min_collateral_factor_for_open_interest(
+ data_store: IDataStoreDispatcher, market: Market, open_interest_delta: i256, is_long: bool
+) -> u256 {
+ let mut open_interest: u256 = get_open_interest_for_market_is_long(
+ data_store, @market, is_long
+ );
+ open_interest = calc::sum_return_uint_256(open_interest, open_interest_delta);
+ let multiplier_factor = get_min_collateral_factor_for_open_interest_multiplier(
+ data_store, market.market_token, is_long
+ );
+ apply_factor_u256(open_interest, multiplier_factor)
+}
+
+// Get the total amount of position collateral for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// 'collateral_token' - the collateral token to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the total amount of position collateral for a market
+fn get_collateral_sum(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ divisor: u256
+) -> u256 {
+ error_utils::check_division_by_zero(divisor, 'get_collaral_sum');
+ data_store.get_u256(keys::collateral_sum_key(market, collateral_token, is_long)) / divisor
+}
+
+// Get the reserve factor for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// The reserve factor for a market
+fn get_reserve_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::reserve_factor_key(market, is_long))
+}
+
+// Get open interest reserve factor
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// The open interest reserve factor
+fn get_open_interest_reserve_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::open_interest_reserve_factor_key(market, is_long))
+}
+
+// Get the max pnl factor
+// # Arguments
+// `data_store` - the data store to use
+// `pnl_factor_type` the type of the pnl factor
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// The max pnl factor
+fn get_max_pnl_factor(
+ data_store: IDataStoreDispatcher,
+ pnl_factor_type: felt252,
+ market: ContractAddress,
+ is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::max_pnl_factor_key(pnl_factor_type, market, is_long))
+}
+
+// Get the min pnl factor after Adl
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// The min pnl factor after adl
+fn get_min_pnl_factor_after_adl(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::min_pnl_factor_after_adl_key(market, is_long))
+}
+
+// Get the funding factor for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// # Returns
+// the funding factor for a market
+fn get_funding_factor(data_store: IDataStoreDispatcher, market: ContractAddress) -> u256 {
+ data_store.get_u256(keys::funding_factor_key(market))
+}
+
+// Get the funding exponent factor for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// # Returns
+// the funding exponent factor for a market
+fn get_funding_exponent_factor(data_store: IDataStoreDispatcher, market: ContractAddress) -> u256 {
+ data_store.get_u256(keys::funding_exponent_factor_key(market))
+}
+
+// Get the funding fee amount per size for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `collateral_token` - the collateral token to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the funding fee amount per size for a market
+fn get_funding_fee_amount_per_size(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::funding_fee_amount_per_size_key(market, collateral_token, is_long))
}
-/// Gets the enabled market. This function will revert if the market does not exist or is not enabled.
-/// # Arguments
-/// * `dataStore` - DataStore
-/// * `marketAddress` - The address of the market.
-fn get_enabled_market(data_store: IDataStoreDispatcher, market_address: ContractAddress) -> Market {
- //TODO
- Market {
- market_token: Zeroable::zero(),
- index_token: Zeroable::zero(),
- long_token: Zeroable::zero(),
- short_token: Zeroable::zero(),
+// Get the claimable funding fee amount per size for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `collateral_token` - the collateral token to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the claimable funding fee amount per size for a market
+fn get_claimable_funding_amount_per_size(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool
+) -> u256 {
+ data_store
+ .get_u256(keys::claimable_funding_amount_per_size_key(market, collateral_token, is_long))
+}
+
+// Apply delta to the funding fee amount per size for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `collateral_token` - the collateral token to check
+// `is_long` - whether to check the long or short side
+// `delta` - the delta to increment by
+fn apply_delta_to_funding_fee_per_size(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ delta: u256
+) {
+ if delta == 0 {
+ return;
+ }
+ let error: felt252 = 0;
+ let delta = to_signed(delta, true);
+ let next_value: u256 = data_store
+ .apply_delta_to_u256(
+ keys::funding_fee_amount_per_size_key(market, collateral_token, is_long),
+ delta,
+ error //Error doesnt exist on solidity function, i just added it because of the merge of Library #1
+ );
+ let delta = to_unsigned(delta);
+ event_emitter
+ .emit_funding_fee_amount_per_size_updated(
+ market, collateral_token, is_long, delta, next_value
+ );
+}
+
+// Apply delta to the claimable funding fee amount per size for a market
+// # Arguments
+// `data_store` - the data store to use
+// `market` - the market to check
+// `collateral_token` - the collateral token to check
+// `is_long` - whether to check the long or short side
+// `delta` - the delta to increment by
+fn apply_delta_to_claimable_funding_amount_per_size(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ collateral_token: ContractAddress,
+ is_long: bool,
+ delta: u256
+) {
+ if delta == 0 {
+ return;
+ }
+ let next_value: u256 = data_store
+ .apply_delta_to_u256(
+ keys::claimable_funding_amount_per_size_key(market, collateral_token, is_long),
+ to_signed(delta, true),
+ 0
+ );
+ event_emitter
+ .emit_claimable_funding_amount_per_size_updated(
+ market, collateral_token, is_long, delta, next_value
+ );
+}
+
+// Get the number of seconds since funding was updated for a market
+// `data_store` - the data store to use
+// `market` - the market to check
+// # Returns
+// the number of seconds since funding was updated for a market
+fn get_seconds_since_funding_updated(
+ data_store: IDataStoreDispatcher, market: ContractAddress
+) -> u256 {
+ //Error on this one but its normal the function is not create yet
+ let updated_at: u256 = data_store.get_u256(keys::funding_updated_at_key(market));
+ if (updated_at == 0) {
+ return 0;
+ }
+ let block_time_stamp = starknet::info::get_block_timestamp().into();
+ block_time_stamp - updated_at
+}
+
+// Get the funding factor per second for a market
+// `data_store` - the data store to use
+// `market` - the market to check
+// `diff_usd` - the difference between the long and short open interest
+// `total_open_interest` - the total open interest
+fn get_funding_factor_per_second(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ diff_usd: u256,
+ total_open_interest: u256
+) -> u256 {
+ let stable_funding_factor: u256 = data_store.get_u256(keys::stable_funding_factor_key(market));
+
+ if (stable_funding_factor > 0) {
+ return stable_funding_factor;
+ };
+
+ if (diff_usd == 0) {
+ return 0;
+ }
+
+ if (total_open_interest == 0) {
+ MarketError::UNABLE_TO_GET_FUNDING_FACTOR_EMPTY_OPEN_INTEREST(total_open_interest);
+ }
+
+ let funding_factor: u256 = get_funding_factor(data_store, market);
+
+ let funding_exponent_factor: u256 = get_funding_exponent_factor(data_store, market);
+ let diff_usd_after_exponent: u256 = apply_exponent_factor(diff_usd, funding_exponent_factor);
+
+ let diff_usd_to_open_interest_factor: u256 = to_factor(
+ diff_usd_after_exponent, total_open_interest
+ );
+
+ return apply_factor_u256(diff_usd_to_open_interest_factor, funding_factor);
+}
+
+// Get the borrowing factor for a market
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the borrowing factor for a market
+fn get_borrowing_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::borrowing_factor_key(market, is_long))
+}
+
+// Get the borrowing exponent factor for a market
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the borrowing exponent factor for a market
+fn get_borrowing_exponent_factor(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::borrowing_exponent_factor_key(market, is_long))
+}
+
+// Get the cumulative borrowing factor for a market
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// # Returns
+// the cumulative borrowing factor for a market
+fn get_cumulative_borrowing_factor(
+ data_store: @IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ let data_store_n: IDataStoreDispatcher = *data_store;
+ data_store_n.get_u256(keys::cumulative_borrowing_factor_key(market, is_long))
+}
+
+// Increment the cumulative borrowing factor
+// `data_store` - the data store to use
+// `market` - the market to check
+// `event_emitter` - the event emitter
+// `is_long` - whether to check the long or short side
+// `delta` - the increase amount
+fn increment_cumulative_borrowing_factor(
+ data_store: IDataStoreDispatcher,
+ event_emitter: IEventEmitterDispatcher,
+ market: ContractAddress,
+ is_long: bool,
+ delta: u256
+) {
+ let next_cumulative_borrowing_factor = data_store
+ .increment_u256(keys::cumulative_borrowing_factor_key(market, is_long), delta);
+
+ event_emitter
+ .emit_cumulative_borrowing_factor_updated(
+ market, is_long, delta, next_cumulative_borrowing_factor
+ );
+}
+
+// Get the timestamp of when the cumulative borrowing factor was last updated
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// #Return
+// the timestamp of when the cumulative borrowing factor was last updated
+fn get_cumulative_borrowing_factor_updated_at(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::cumulative_borrowing_factor_updated_at_key(market, is_long))
+}
+
+// Get the number of seconds since the cumulative borrowing factor was last updated
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// #Return
+// the number of seconds since the cumulative borrowing factor was last updated
+fn get_seconds_since_cumulative_borrowing_factor_updated(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ let updated_at: u256 = get_cumulative_borrowing_factor_updated_at(data_store, market, is_long);
+ if (updated_at == 0) {
+ return 0;
+ }
+ let block_time_stamp = starknet::info::get_block_timestamp().into();
+ block_time_stamp - updated_at
+}
+
+// Update the total borrowing amount after a position changes size
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// `prev_position_size_in_usd` - the previous position size in USD
+// `prev_position_borrowing_factor` - the previous position borrowing factor
+// `next_position_size_in_usd` - the next position size in USD
+// `next_position_borrowing_factor` - the next position borrowing factor
+fn update_total_borrowing(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ is_long: bool,
+ prev_position_size_in_usd: u256,
+ prev_position_borrowing_factor: u256,
+ next_position_size_in_usd: u256,
+ next_position_borrowing_factor: u256
+) {
+ let total_borrowing: u256 = get_next_total_borrowing(
+ data_store,
+ market,
+ is_long,
+ prev_position_size_in_usd,
+ prev_position_borrowing_factor,
+ next_position_size_in_usd,
+ next_position_borrowing_factor
+ );
+
+ set_total_borrowing(data_store, market, is_long, total_borrowing);
+}
+
+// Get the next total borrowing amount after a position changes size
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// `prev_position_size_in_usd` - the previous position size in USD
+// `prev_position_borrowing_factor` - the previous position borrowing factor
+// `next_position_size_in_usd` - the next position size in USD
+// `next_position_borrowing_factor` - the next position borrowing factor
+fn get_next_total_borrowing(
+ data_store: IDataStoreDispatcher,
+ market: ContractAddress,
+ is_long: bool,
+ prev_position_size_in_usd: u256,
+ prev_position_borrowing_factor: u256,
+ next_position_size_in_usd: u256,
+ next_position_borrowing_factor: u256
+) -> u256 {
+ let mut total_borrowing: u256 = get_total_borrowing(data_store, market, is_long);
+ total_borrowing -= apply_factor_u256(prev_position_size_in_usd, prev_position_borrowing_factor);
+ total_borrowing += apply_factor_u256(next_position_size_in_usd, next_position_borrowing_factor);
+
+ total_borrowing
+}
+
+// Get the next total borrowing amount after a position changes size
+// `data_store` - the data store to use
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// `long_token` - the long token of the market
+// `short_token` - the short token of the market
+fn get_next_cumulative_borrowing_factor(
+ data_store: IDataStoreDispatcher, market: Market, prices: MarketPrices, is_long: bool,
+) -> (u256, u256) {
+ let duration_in_seconds: u256 = get_seconds_since_cumulative_borrowing_factor_updated(
+ data_store, market.market_token, is_long
+ );
+ let borrowing_factor_per_second: u256 = get_borrowing_factor_per_second(
+ data_store, market, prices, is_long
+ );
+
+ let cumulative_borrowing_factor: u256 = get_cumulative_borrowing_factor(
+ @data_store, market.market_token, is_long
+ );
+
+ let delta: u256 = duration_in_seconds * borrowing_factor_per_second;
+ let next_cumulative_borrowing_factor: u256 = cumulative_borrowing_factor + delta;
+ (next_cumulative_borrowing_factor, delta)
+}
+
+// Get the borrowing factor per second
+// `data_store` - the data store to use
+// `market` - the market to get the borrowing factor per second for
+// `prices` - prices the prices of the market tokens
+// `is_long` - whether to get the factor for the long or short side
+fn get_borrowing_factor_per_second(
+ data_store: IDataStoreDispatcher, market: Market, prices: MarketPrices, is_long: bool
+) -> u256 {
+ let reserved_usd: u256 = get_reserved_usd(data_store, @market, @prices, is_long);
+
+ if (reserved_usd == 0) {
+ return 0;
+ }
+
+ // check if the borrowing fee for the smaller side should be skipped
+ // if skipBorrowingFeeForSmallerSide is true, and the longOpenInterest is exactly the same as the shortOpenInterest
+ // then the borrowing fee would be charged for both sides, this should be very rare
+ let skip_borrowing_fee_for_smaller_side: bool = data_store
+ .get_bool(keys::skip_borrowing_fee_for_smaller_side());
+
+ let market_snap = @market;
+ if (skip_borrowing_fee_for_smaller_side) {
+ let long_open_interest: u256 = get_open_interest_for_market_is_long(
+ data_store, market_snap, true
+ );
+ let short_open_interest: u256 = get_open_interest_for_market_is_long(
+ data_store, market_snap, false
+ );
+
+ // if getting the borrowing factor for longs and if the longOpenInterest
+ // is smaller than the shortOpenInterest, then return zero
+ if (is_long && long_open_interest < short_open_interest) {
+ return 0;
+ }
+ // if getting the borrowing factor for shorts and if the shortOpenInterest
+ // is smaller than the longOpenInterest, then return zero
+ if (!is_long && short_open_interest < long_open_interest) {
+ return 0;
+ }
+ }
+ let pool_usd: u256 = get_pool_usd_without_pnl(data_store, @market, @prices, is_long, false);
+
+ if (pool_usd == 0) {
+ MarketError::UNABLE_TO_GET_BORROWING_FACTOR_EMPTY_POOL_USD(pool_usd);
}
-}
-/// Returns the primary prices for the market tokens.
-/// # Parameters
-/// - `oracle`: The Oracle instance.
-/// - `market`: The market values.
-fn get_market_prices(oracle: IOracleDispatcher, market: Market) -> MarketPrices {
- //TODO
- Default::default()
-}
+ let borrowing_exponent_factor: u256 = get_borrowing_exponent_factor(
+ data_store, market.market_token, is_long
+ );
+ let reserved_usd_after_exponent: u256 = apply_exponent_factor(
+ reserved_usd, borrowing_exponent_factor
+ );
-/// Validates that the amount of tokens required to be reserved is below the configured threshold.
-/// # Arguments
-/// * `dataStore`: DataStore - The data storage instance.
-/// * `market`: Market values to consider.
-/// * `prices`: Prices of the market tokens.
-/// * `isLong`: A boolean flag to indicate whether to check the long or short side.
-fn validate_reserve(
- data_store: IDataStoreDispatcher, market: Market, prices: @MarketPrices, is_long: bool
-) { //TODO
-}
+ let reserved_usd_to_pool_factor: u256 = to_factor(reserved_usd_after_exponent, pool_usd);
+ let borrowing_factor: u256 = get_borrowing_factor(data_store, market.market_token, is_long);
-/// Validates that the pending pnl is below the allowed amount.
-/// # Arguments
-/// * `dataStore` - DataStore
-/// * `market` - The market to check
-/// * `prices` - The prices of the market tokens
-/// * `pnlFactorType` - The pnl factor type to check
-fn validate_max_pnl(
- data_store: IDataStoreDispatcher,
- market: Market,
- prices: @MarketPrices,
- pnl_factor_type_for_longs: felt252,
- pnl_factor_type_for_shorts: felt252,
-) { //TODO
+ apply_factor_u256(reserved_usd_to_pool_factor, borrowing_factor)
}
-/// Validates the token balance for a single market.
-/// # Arguments
-/// * `data_store` - The data_store dispatcher
-/// * `market` - Address of the market to check.
-fn validate_market_token_balance_with_address(
- data_store: IDataStoreDispatcher, market: ContractAddress
-) { //TODO
-}
+// Get the total pending borrowing fees
+// `data_store` - the data store to use
+// `market` - the market to get the borrowing factor per second for
+// `long_token` - the long token of the market
+// `short_token` - the short token of the market
+// `is_long` - whether to get the factor for the long or short side
+fn get_total_pending_borrowing_fees(
+ data_store: IDataStoreDispatcher, market: Market, prices: MarketPrices, is_long: bool
+) -> u256 {
+ let open_interest: u256 = get_open_interest_for_market_is_long(data_store, @market, is_long);
+
+ let (next_cumulative_borrowing_factor, _) = get_next_cumulative_borrowing_factor(
+ data_store, market, prices, is_long
+ );
+
+ let total_borrowing: u256 = get_total_borrowing(data_store, market.market_token, is_long);
-fn validate_market_token_balance(data_store: IDataStoreDispatcher, market: Market) { //TODO
+ apply_factor_u256(open_interest, next_cumulative_borrowing_factor) - total_borrowing
}
-fn validate_markets_token_balance(data_store: IDataStoreDispatcher, market: Span) { //TODO
+// Get the total borrowing value
+// the total borrowing value is the sum of position.borrowingFactor * position.size / (10 ^ 30)
+// for all positions of the market
+// if borrowing APR is 1000% for 100 years, the cumulativeBorrowingFactor could be as high as 100 * 1000 * (10 ** 30)
+// since position.size is a USD value with 30 decimals, under this scenario, there may be overflow issues
+// if open interest exceeds (2 ** 256) / (10 ** 30) / (100 * 1000 * (10 ** 30)) => 1,157,920,900,000 USD
+// `data_store` - the data store to use
+// `market` - the market to get the borrowing factor per second for
+// `is_long` - whether to get the factor for the long or short side
+// #Return
+// The total borrowing value
+fn get_total_borrowing(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool
+) -> u256 {
+ data_store.get_u256(keys::total_borrowing_key(market, is_long))
}
-/// Gets a list of market values based on an input array of market addresses.
-/// # Parameters
-/// * `swap_path`: A list of market addresses.
-fn get_swap_path_markets(
- data_store: IDataStoreDispatcher, swap_path: Span32
-) -> Array { //TODO
- Default::default()
+// Set the total borrowing value
+// `data_store` - the data store to use
+// `market` - the market to get the borrowing factor per second for
+// `is_long` - whether to get the factor for the long or short side
+// `value` - the value to set to
+fn set_total_borrowing(
+ data_store: IDataStoreDispatcher, market: ContractAddress, is_long: bool, value: u256
+) {
+ data_store.set_u256(keys::total_borrowing_key(market, is_long), value)
}
-/// Gets the USD value of a pool.
-/// The value of a pool is determined by the worth of the liquidity provider tokens in the pool,
-/// minus any pending trader profit and loss (PNL).
-/// We use the token index prices for this calculation and ignore price impact. The reasoning is that
-/// if all positions were closed, the net price impact should be zero.
-/// # Arguments
-/// * `data_store` - The DataStore structure.
-/// * `market` - The market values.
-/// * `long_token_price` - Price of the long token.
-/// * `short_token_price` - Price of the short token.
-/// * `index_token_price` - Price of the index token.
-/// * `maximize` - Whether to maximize or minimize the pool value.
-/// # Returns
-/// Returns the value information of a pool.
-fn get_pool_value_info(
- data_store: IDataStoreDispatcher,
- market: Market,
- index_token_price: Price,
- long_token_price: Price,
- short_token_price: Price,
- pnl_factor_type: felt252,
- maximize: bool
-) -> MarketPoolValueInfo {
- // TODO
- Default::default()
+// Convert a number of market tokens to its USD value
+// `usd_value` - the input USD value
+// `pool_value` - the value of the pool
+// `supply` - the supply of the market tokens
+fn usd_to_market_token_amount(usd_value: u256, pool_value: u256, supply: u256) -> u256 {
+ // if the supply and poolValue is zero, use 1 USD as the token price
+ if (supply == 0 && pool_value == 0) {
+ return float_to_wei(usd_value);
+ }
+
+ // if the supply is zero and the poolValue is more than zero,
+ // then include the poolValue for the amount of tokens minted so that
+ // the market token price after mint would be 1 USD
+ if (supply == 0 && pool_value > 0) {
+ return float_to_wei(pool_value + usd_value);
+ }
+
+ // round market tokens down
+ mul_div(supply, usd_value, pool_value)
}
-/// Get the capped pending pnl for a market
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market to get the pending PNL for.
-/// * `is_long` - Whether to get the long or short pending PNL.
-/// * `pnl` - The uncapped pnl of the market.
-/// * `pool_usd` - The USD value of the pool.
-/// * `pnl_factor_type` - The pnl factor type to use.
-/// # Returns
-/// The net pending pnl for a market
-fn get_capped_pnl(
- data_store: IDataStoreDispatcher,
- market: ContractAddress,
- is_long: bool,
- pnl: i128,
- pool_usd: u128,
- pnl_factor_type: felt252
-) -> i128 {
- // TODOs
- 0
+// Set the total borrowing value
+// `market_token_amount` - the input number of market tokens
+// `pool_value` - the value of the pool
+// `supply` - the supply of the market tokens
+// #Return
+// The USD value of the market tokens
+fn market_token_amount_to_usd(market_token_amount: u256, pool_value: u256, supply: u256) -> u256 {
+ if (supply == 0) {
+ MarketError::EMPTY_MARKET_TOKEN_SUPPLY(supply);
+ }
+
+ mul_div(pool_value, market_token_amount, supply)
}
+// Validate that the specified market exists and is enabled
+// `data_store` - the data store to use
+// `market_add` the address of the market
+fn validate_enabled_market_check(
+ data_store: IDataStoreDispatcher, market_address: ContractAddress
+) {
+ let market: Market = data_store.get_market(market_address);
+ validate_enabled_market(data_store, market);
+}
-/// Validata that the specified market exists and is enabled
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market to validate.
+// Validate that the specified market exists and is enabled
+// `data_store` - the data store to use
+// `market` - the market to check
fn validate_enabled_market(data_store: IDataStoreDispatcher, market: Market) {
- assert(!market.market_token.is_zero(), MarketError::EMPTY_MARKET);
- let is_market_disabled = data_store.get_bool(keys::is_market_disabled_key(market.market_token));
+ assert(market.market_token != 0.try_into().unwrap(), MarketError::EMPTY_MARKET);
- match is_market_disabled {
- Option::Some(result) => {
- assert(!result, MarketError::DISABLED_MARKET);
- },
- Option::None => {
- panic_with_felt252(MarketError::DISABLED_MARKET);
- }
- };
+ let is_market_disabled: bool = data_store
+ .get_bool(keys::is_market_disabled_key(market.market_token));
+
+ if (is_market_disabled) {
+ MarketError::DISABLED_MARKET(is_market_disabled);
+ }
}
+// Validate that the positions can be opened in the given market
+// `market` - the market to check
+fn validate_position_market_check(data_store: IDataStoreDispatcher, market: Market) {
+ validate_enabled_market(data_store, market);
-/// Validata that the specified market exists and is enabled
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market to validate.
-fn validate_enabled_market_address(
- data_store: IDataStoreDispatcher, market: ContractAddress
-) { // TODO
+ assert(!is_swap_only_market(market), MarketError::INVALID_POSITION_MARKET);
}
+fn validate_position_market(data_store: IDataStoreDispatcher, market_add: ContractAddress) {
+ let market: Market = data_store.get_market(market_add);
+ validate_position_market_check(data_store, market);
+}
-/// Validata if the given token is a collateral token of the market
-/// # Arguments
-/// * `market` - The market to validate.
-/// * `token` - The token to check
-fn validate_market_collateral_token(market: Market, token: ContractAddress) { // TODO
+// Check if a market only supports swaps and not positions
+// `market` - the market to check
+fn is_swap_only_market(market: Market) -> bool {
+ market.index_token.is_zero()
}
-/// Get the max position impact factor for liquidations
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-fn get_max_position_impact_factor_for_liquidations(
- data_store: IDataStoreDispatcher, market: ContractAddress
-) -> u128 {
- // TODOs
- 0
+// Check if the given token is a collateral token of the market
+// `market` - the market to check
+// `token` - the token to check
+fn is_market_collateral_token(market: Market, token: ContractAddress) -> bool {
+ market.long_token == token || market.short_token == token
}
-/// Get the min collateral factor
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-fn get_min_collateral_factor(data_store: IDataStoreDispatcher, market: ContractAddress) -> u128 {
- // TODOs
- 0
+// Validate if the given token is a collateral token of the market
+// `market` - the market to check
+// `token` - the token to check
+fn validate_market_collateral_token(market: Market, token: ContractAddress) {
+ if (!is_market_collateral_token(market, token)) {
+ MarketError::INVALID_MARKET_COLLATERAL_TOKEN(market.market_token, token);
+ }
}
+// Get the enabled market, revert if the market does not exist or is not enabled
+// `data_store - DataStore
+// `market_add` - the address of the market
+fn get_enabled_market(data_store: IDataStoreDispatcher, market_add: ContractAddress) -> Market {
+ let market: Market = data_store.get_market(market_add);
+ validate_enabled_market(data_store, market);
+ market
+}
-/// Get the min collateral factor for open interest
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-/// * `open_interest_delta` - The change in open interest.
-/// * `is_long` - Whether it is for the long or short side
-fn get_min_collateral_factor_for_open_interest(
- data_store: IDataStoreDispatcher, market: Market, open_interest_delta: i128, is_long: bool
-) -> u128 {
- // TODOs
- 0
+fn get_swap_path_market(data_store: IDataStoreDispatcher, market_add: ContractAddress) -> Market {
+ let market: Market = data_store.get_market(market_add);
+ validate_swap_market(data_store, market);
+ market
}
+// Get a list of market values based on an input array of market addresses
+// `swap_path` - list of market addresses
+fn get_swap_path_markets(
+ data_store: IDataStoreDispatcher, swap_path: Span32
+) -> Array {
+ let mut markets: Array = ArrayTrait::new();
+ let mut i: u32 = 0;
+ let length: u32 = swap_path.len();
+
+ loop {
+ if i == length {
+ break;
+ }
+ let market_adress_prev = swap_path.get(i);
+ let market_adress: ContractAddress = *market_adress_prev.unwrap().unbox();
+ markets.append(get_swap_path_market(data_store, market_adress));
+ i += 1;
+ };
+ markets
+}
-/// Update the funding state
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `event_emitter` - The event emitter.
-/// * `market` - The market.
-/// * `prices` - The market prices.
-fn update_funding_state(
- data_store: IDataStoreDispatcher,
- event_emitter: IEventEmitterDispatcher,
- market: Market,
- prices: MarketPrices
-) { // TODO
+fn validate_swap_path(data_store: IDataStoreDispatcher, token_swap_path: Span32) {
+ let max_swap_path_length: u256 = data_store.get_u256(keys::max_swap_path_length());
+ let token_swap_path_length: u32 = token_swap_path.len();
+
+ if (token_swap_path_length.into() > max_swap_path_length) {
+ MarketError::MAX_SWAP_PATH_LENGTH_EXCEEDED(token_swap_path_length, max_swap_path_length);
+ }
+
+ let mut i: u32 = 0;
+ loop {
+ if i == token_swap_path_length {
+ break;
+ }
+ let market_prev = token_swap_path.get(i);
+ let market: ContractAddress = *market_prev.unwrap().unbox();
+ validate_swap_market_with_address(data_store, market);
+ i += 1;
+ };
}
-/// Update the cumulative borrowing factor for a market
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `event_emitter` - The event emitter.
-/// * `market` - The market.
-/// * `prices` - The market prices.
-/// * `is_long` - Whether to update the long or short side.
-fn update_cumulative_borrowing_factor(
+// Validate that the pending pnl is below the allowed amount
+// `data_store` - DataStore
+// `market` - the market to check
+// `prices` - the prices of the market tokens
+// `pnl_factor_type` - the pnl factor type to check
+fn validate_max_pnl(
data_store: IDataStoreDispatcher,
- event_emitter: IEventEmitterDispatcher,
market: Market,
prices: MarketPrices,
- is_long: bool
-) { // TODO
+ pnl_factor_type_for_longs: felt252,
+ pnl_factor_type_for_shorts: felt252
+) {
+ let (is_pnl_factor_exceeded_for_longs, pnl_to_pool_factor_for_longs, max_pnl_factor_for_longs) =
+ is_pnl_factor_exceeded_check(
+ data_store, market, prices, true, pnl_factor_type_for_longs,
+ );
+
+ if (is_pnl_factor_exceeded_for_longs) {
+ MarketError::PNL_EXCEEDED_FOR_LONGS(is_pnl_factor_exceeded_for_longs);
+ }
+
+ let (
+ is_pnl_factor_exceeded_for_shorts, pnl_to_pool_factor_for_shorts, max_pnl_factor_for_shorts
+ ) =
+ is_pnl_factor_exceeded_check(
+ data_store, market, prices, false, pnl_factor_type_for_shorts,
+ );
+
+ if (is_pnl_factor_exceeded_for_shorts) {
+ MarketError::PNL_EXCEEDED_FOR_SHORTS(is_pnl_factor_exceeded_for_shorts);
+ }
}
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-/// * `is_long` - Whether to update the long or short side.
-/// * `prev_position_size_in_usd` - The previous position size in USD.
-/// * `prev_position_borrowing_factor` - The previous position borrowing factor.
-/// * `next_position_size_in_usd` - The next position size in USD.
-/// * `next_position_borrowing_factor` - The next position borrowing factor.
-fn update_total_borrowing(
+// Check if the pending pnl exceeds the allowed amount
+// `data_store` - DataStore
+// `oracle` - Oracle
+// `market` - the market to check
+// `is_long` - whether to check the long or short side
+// `pnl_factor_type` - the pnl factor type to check
+fn is_pnl_factor_exceeded(
data_store: IDataStoreDispatcher,
- market: ContractAddress,
+ oracle: IOracleDispatcher,
+ market_add: ContractAddress,
is_long: bool,
- prev_position_size_in_usd: u128,
- prev_position_borrowing_factor: u128,
- next_position_size_in_usd: u128,
- next_position_borrowing_factor: u128
-) { // TODO
+ pnl_factor_type: felt252
+) -> (bool, i256, u256) {
+ let market: Market = get_enabled_market(data_store, market_add);
+ let prices: MarketPrices = get_market_prices(oracle, market);
+
+ is_pnl_factor_exceeded_check(data_store, market, prices, is_long, pnl_factor_type)
}
+// Check if the pending pnl exceeds the allowed amount
+// `data_store` - DataStore
+// `market` - the market to check
+// `prices` - the prices of the market tokens
+// `is_long` - whether to check the long or short side
+// `pnl_factor_type` - the pnl factor type to check
+fn is_pnl_factor_exceeded_check(
+ data_store: IDataStoreDispatcher,
+ market: Market,
+ prices: MarketPrices,
+ is_long: bool,
+ pnl_factor_type: felt252
+) -> (bool, i256, u256) {
+ let pnl_to_pool_factor: i256 = get_pnl_to_pool_factor_from_prices(
+ data_store, @market, @prices, is_long, true
+ );
+ let max_pnl_factor: u256 = get_max_pnl_factor(
+ data_store, pnl_factor_type, market.market_token, is_long
+ );
-/// Gets the total supply of the marketToken.
-/// # Arguments
-/// * `market_token` - The market token whose total supply is to be retrieved.
-/// # Returns
-/// The total supply of the given marketToken.
-fn get_market_token_supply(market_token: IMarketTokenDispatcher) -> u128 {
- // TODO
- market_token.total_supply()
-}
+ let is_exceeded: bool = pnl_to_pool_factor > Zeroable::zero()
+ && to_unsigned(pnl_to_pool_factor) > max_pnl_factor;
-/// Converts a number of market tokens to its USD value.
-/// # Arguments
-/// * `market_token_amount` - The input number of market tokens.
-/// * `pool_value` - The value of the pool.
-/// * `supply` - The supply of market tokens.
-/// # Returns
-/// The USD value of the market tokens.
-fn market_token_amount_to_usd(
- market_token_amount: u128, pool_value: u128, supply: u128
-) -> u128 { // TODO
- 0
+ (is_exceeded, pnl_to_pool_factor, max_pnl_factor)
}
+fn get_ui_fee_factor(data_store: IDataStoreDispatcher, account: ContractAddress) -> u256 {
+ let max_ui_fee_factor: u256 = data_store.get_u256(keys::max_ui_fee_factor());
+ let ui_fee_factor: u256 = data_store.get_u256(keys::ui_fee_factor_key(account));
-/// Get the borrowing factor per second.
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-/// * `prices` - The prices of the market tokens.
-/// * `is_long` - Whether to get the factor for the long or short side
-/// # Returns
-/// The borrowing factor per second.
-fn get_borrowing_factor_per_second(
- data_store: IDataStoreDispatcher, market: Market, prices: MarketPrices, is_long: bool
-) -> u128 {
- // TODO
- 0
+ if ui_fee_factor < max_ui_fee_factor {
+ return ui_fee_factor;
+ } else {
+ return max_ui_fee_factor;
+ }
}
-/// Get the borrowing factor per second.
-/// # Arguments
-/// * `data_store` - The `DataStore` contract dispatcher.
-/// * `market` - Market to check.
-/// * `index_token_price` - Price of the market's index token.
-/// * `long_token_price` - Price of the market's long token.
-/// * `short_token_price` - Price of the market's short token.
-/// * `pnl_factor_type` - The pnl factor type.
-/// * `maximize` - Whether to maximize or minimize the net PNL.
-/// # Returns
-/// Returns an integer representing the calculated market token price and MarketPoolValueInfo struct containing additional information related to market pool value.
-
-fn get_market_token_price(
+fn set_ui_fee_factor(
data_store: IDataStoreDispatcher,
- market: Market,
- index_token_price: Price,
- long_token_price: Price,
- short_token_price: Price,
- pnl_factor_type: felt252,
- maximize: bool
-) -> (i128, MarketPoolValueInfo) {
- // TODO
- (0, Default::default())
+ event_emitter: IEventEmitterDispatcher,
+ account: ContractAddress,
+ ui_fee_factor: u256
+) {
+ let max_ui_fee_factor: u256 = data_store.get_u256(keys::max_ui_fee_factor());
+
+ if (ui_fee_factor > max_ui_fee_factor) {
+ MarketError::UI_FEE_FACTOR_EXCEEDED(ui_fee_factor, max_ui_fee_factor);
+ }
+
+ data_store.set_u256(keys::ui_fee_factor_key(account), ui_fee_factor);
+
+ event_emitter.emit_ui_fee_factor_updated(account, ui_fee_factor);
}
-/// Get the net pending pnl for a market
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market to get the pending PNL for.
-/// * `index_token_price` - The price of the index token.
-/// * `maximize` - Whether to maximize or minimize the net PNL.
-/// # Returns
-/// The net pending pnl for a market
-fn get_net_pnl(
- data_store: IDataStoreDispatcher, market: @Market, index_token_price: @Price, maximize: bool
-) -> i128 {
- // TODO
- 0
+fn validate_market_token_balance_array(data_store: IDataStoreDispatcher, markets: Array) {
+ let length: u32 = markets.len();
+ let mut i: u32 = 0;
+ loop {
+ if i == length {
+ break;
+ }
+ validate_market_token_balance_check(data_store, *markets.at(i));
+ i += 1;
+ };
}
-/// The sum of open interest and pnl for a market
-// get_open_interest_in_tokens * token_price would not reflect pending positive pnl
-// for short positions, so get_open_interest_with_pnl should be used if that info is needed
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market.
-/// * `index_token_price` - The price of the index token.
-/// * `is_long` - Whether to check the long or short side
-/// * `maximize` - Whether to maximize or minimize the net PNL.
-/// # Returns
-/// The net pending pnl for a market
-fn get_open_interest_with_pnl(
- data_store: IDataStoreDispatcher,
- market: Market,
- index_token_price: Price,
- is_long: bool,
- maximize: bool
-) -> i128 {
- // TODO
- 0
+fn validate_market_token_balance_span(data_store: IDataStoreDispatcher, markets: Span) {
+ let length: u32 = markets.len();
+ let mut i: u32 = 0;
+ loop {
+ if i == length {
+ break;
+ }
+ validate_market_token_balance_check(data_store, *markets.at(i));
+ i += 1;
+ };
+}
+
+fn validate_market_address_token_balance(
+ data_store: IDataStoreDispatcher, market_add: ContractAddress
+) {
+ let market: Market = get_enabled_market(data_store, market_add);
+ validate_market_token_balance_check(data_store, market);
}
+fn validate_market_token_balance_check(data_store: IDataStoreDispatcher, market: Market) {
+ validate_market_token_balance_with_token(data_store, market, market.long_token);
-/// Get the virtual inventory for swaps
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `market` - The market address.
-/// # Returns
-/// has virtual inventory, virtual long token inventory, virtual short token inventory
-fn get_virtual_inventory_for_swaps(
- data_store: IDataStoreDispatcher, market: ContractAddress,
-) -> (bool, u128, u128) {
- // TODO
- (false, 0, 0)
+ if (market.long_token == market.short_token) {
+ return;
+ }
+ validate_market_token_balance_with_token(data_store, market, market.short_token);
}
+fn validate_market_token_balance_with_token(
+ data_store: IDataStoreDispatcher, market: Market, token: ContractAddress
+) {
+ assert(
+ market.market_token.is_non_zero() && token.is_non_zero(),
+ MarketError::EMPTY_ADDRESS_IN_MARKET_TOKEN_BALANCE_VALIDATION
+ );
+ let balance: u256 = IERC20Dispatcher { contract_address: token }
+ .balance_of(market.market_token)
+ .low
+ .into();
+ let expected_min_balance: u256 = get_expected_min_token_balance(data_store, market, token);
+ assert(balance >= expected_min_balance, MarketError::INVALID_MARKET_TOKEN_BALANCE);
+
+ // funding fees can be claimed even if the collateral for positions that should pay funding fees
+ // hasn't been reduced yet
+ // due to that, funding fees and collateral is excluded from the expectedMinBalance calculation
+ // and validated separately
+
+ // use 1 for the getCollateralSum divisor since getCollateralSum does not sum over both the
+ // longToken and shortToken
+ let mut collateral_amount: u256 = get_collateral_sum(
+ data_store, market.market_token, token, true, 1
+ );
+ collateral_amount += get_collateral_sum(data_store, market.market_token, token, false, 1);
-/// Get the virtual inventory for positions
-/// # Arguments
-/// * `data_store` - The data store to use.
-/// * `token` - The token to check.
-/// # Returns
-/// has virtual inventory, virtual inventory
-fn get_virtual_inventory_for_positions(
- data_store: IDataStoreDispatcher, token: ContractAddress,
-) -> (bool, i128) {
- // TODO
- (false, 0)
+ if (balance < collateral_amount) {
+ MarketError::INVALID_MARKET_TOKEN_BALANCE_FOR_COLLATERAL_AMOUNT(balance, collateral_amount);
+ }
+
+ let claimable_funding_fee_amount = data_store
+ .get_u256(keys::claimable_funding_amount_key(market.market_token, token));
+
+ // in case of late liquidations, it may be possible for the claimableFundingFeeAmount to exceed the market token balance
+ // but this should be very rare
+ if (balance < claimable_funding_fee_amount) {
+ MarketError::INVALID_MARKET_TOKEN_BALANCE_FOR_CLAIMABLE_FUNDING(
+ balance, claimable_funding_fee_amount
+ );
+ }
}
+fn get_expected_min_token_balance(
+ data_store: IDataStoreDispatcher, market: Market, token: ContractAddress
+) -> u256 {
+ // get the pool amount directly as MarketUtils.get_pool_amount will divide the amount by 2
+ // for markets with the same long and short token
+ let pool_amount: u256 = data_store.get_u256(keys::pool_amount_key(market.market_token, token));
+ let swap_impact_pool_amount: u256 = get_swap_impact_pool_amount(
+ data_store, market.market_token, token
+ );
+ let claimable_collateral_amount: u256 = data_store
+ .get_u256(keys::claimable_collateral_amount_key(market.market_token, token));
+ let claimable_fee_amount: u256 = data_store
+ .get_u256(keys::claimable_fee_amount_key(market.market_token, token));
+ let claimable_ui_fee_amount: u256 = data_store
+ .get_u256(keys::claimable_ui_fee_amount_key(market.market_token, token));
+ let affiliate_reward_amount: u256 = data_store
+ .get_u256(keys::affiliate_reward_key(market.market_token, token));
+ // funding fees are excluded from this summation as claimable funding fees
+ // are incremented without a corresponding decrease of the collateral of
+ // other positions, the collateral of other positions is decreased when
+ // those positions are updated
+ return pool_amount
+ + swap_impact_pool_amount
+ + claimable_collateral_amount
+ + claimable_fee_amount
+ + claimable_ui_fee_amount
+ + affiliate_reward_amount;
+}
diff --git a/src/mock/error.cairo b/src/mock/error.cairo
index e8bb1f25..7c2113a5 100644
--- a/src/mock/error.cairo
+++ b/src/mock/error.cairo
@@ -1,4 +1,5 @@
mod MockError {
+ const ALREADY_INITIALIZED: felt252 = 'already_initialized';
const INVALID_TOTAL_REBATE: felt252 = 'invalid total_rebate';
const INVALID_DISCOUNT_SHARE: felt252 = 'invalid discount_share';
const INVALID_CODE: felt252 = 'invalid code';
diff --git a/src/mock/governable.cairo b/src/mock/governable.cairo
index 79dc73d3..71b83646 100644
--- a/src/mock/governable.cairo
+++ b/src/mock/governable.cairo
@@ -57,9 +57,10 @@ mod Governable {
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl Governable of super::IGovernable {
fn initialize(ref self: ContractState, event_emitter_address: ContractAddress) {
+ assert(self.gov.read().is_zero(), MockError::ALREADY_INITIALIZED);
self
.event_emitter
.write(IEventEmitterDispatcher { contract_address: event_emitter_address });
diff --git a/src/mock/mock_account.cairo b/src/mock/mock_account.cairo
new file mode 100644
index 00000000..89f530a8
--- /dev/null
+++ b/src/mock/mock_account.cairo
@@ -0,0 +1,85 @@
+//! Mock Account for testing.
+
+#[starknet::contract]
+mod MockAccount {
+ // *************************************************************************
+ // IMPORTS
+ // *************************************************************************
+
+ // Core lib imports.
+ use core::zeroable::Zeroable;
+ use starknet::{get_caller_address, ContractAddress};
+ use result::ResultTrait;
+
+ // Local imports.
+ use satoru::oracle::{
+ interfaces::account::{IAccount, IAccountDispatcher, IAccountDispatcherTrait}
+ };
+
+
+ // *************************************************************************
+ // STORAGE
+ // *************************************************************************
+ #[storage]
+ struct Storage {
+ owner: felt252,
+ }
+
+ // *************************************************************************
+ // EXTERNAL FUNCTIONS
+ // *************************************************************************
+ #[external(v0)]
+ impl MockAccount of IAccount {
+ fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 {
+ 1
+ }
+ fn __validate_deploy__(
+ self: @ContractState,
+ class_hash: felt252,
+ contract_address_salt: felt252,
+ owner: felt252,
+ guardian: felt252
+ ) -> felt252 {
+ 1
+ }
+
+ fn change_owner(
+ ref self: ContractState, new_owner: felt252, signature_r: felt252, signature_s: felt252
+ ) {
+ self.owner.write(new_owner);
+ }
+ fn change_guardian(ref self: ContractState, new_guardian: felt252) {}
+
+
+ fn change_guardian_backup(ref self: ContractState, new_guardian_backup: felt252) {}
+
+
+ fn trigger_escape_owner(ref self: ContractState, new_owner: felt252) {}
+
+ fn trigger_escape_guardian(ref self: ContractState, new_guardian: felt252) {}
+
+ fn escape_owner(ref self: ContractState) {}
+
+ fn escape_guardian(ref self: ContractState) {}
+
+ fn cancel_escape(ref self: ContractState) {}
+ fn get_owner(self: @ContractState) -> felt252 {
+ self.owner.read()
+ }
+ fn get_guardian(self: @ContractState) -> felt252 {
+ 1
+ }
+ fn get_guardian_backup(self: @ContractState) -> felt252 {
+ 1
+ }
+ fn get_name(self: @ContractState) -> felt252 {
+ 1
+ }
+ fn get_guardian_escape_attempts(self: @ContractState) -> u32 {
+ 1
+ }
+ fn get_owner_escape_attempts(self: @ContractState) -> u32 {
+ 1
+ }
+ }
+}
diff --git a/src/mock/referral_storage.cairo b/src/mock/referral_storage.cairo
index 2fc2c0eb..9ee76a51 100644
--- a/src/mock/referral_storage.cairo
+++ b/src/mock/referral_storage.cairo
@@ -3,7 +3,6 @@
// *************************************************************************
// IMPORTS
// *************************************************************************
-
// Core lib imports.
use starknet::ContractAddress;
@@ -11,7 +10,7 @@ use starknet::ContractAddress;
use satoru::referral::referral_tier::ReferralTier;
// *************************************************************************
-// Interface of the `OracleStore` contract.
+// Interface of the `ReferralStorage` contract.
// *************************************************************************
#[starknet::interface]
trait IReferralStorage {
@@ -28,7 +27,7 @@ trait IReferralStorage {
/// Set the trader discount share for an affiliate.
/// # Arguments
/// * `account` - The address of the affiliate.
- fn set_referrer_discount_share(ref self: TContractState, discount_share: u128);
+ fn set_referrer_discount_share(ref self: TContractState, discount_share: u256);
/// Set the referral code for a trader.
/// # Arguments
@@ -64,14 +63,14 @@ trait IReferralStorage {
/// * `account` - The address of the affiliate.
/// # Returns
/// The trader discount share.
- fn referrer_discount_shares(self: @TContractState, account: ContractAddress) -> u128;
+ fn referrer_discount_shares(self: @TContractState, account: ContractAddress) -> u256;
/// Get the tier level of an affiliate.
/// # Arguments
/// * `account` - The address of the affiliate.
/// # Returns
/// The tier level of the affiliate.
- fn referrer_tiers(self: @TContractState, account: ContractAddress) -> u128;
+ fn referrer_tiers(self: @TContractState, account: ContractAddress) -> u256;
/// Get the referral info for a trader.
/// # Arguments
@@ -93,13 +92,13 @@ trait IReferralStorage {
/// * `tier_id` - The tier level.
/// * `total_rebate` - The total rebate for the tier (affiliate reward + trader discount).
/// * `discount_share` - The share of the total_rebate for traders.
- fn set_tier(ref self: TContractState, tier_id: u128, total_rebate: u128, discount_share: u128);
+ fn set_tier(ref self: TContractState, tier_id: u256, total_rebate: u256, discount_share: u256);
/// Set the tier for an affiliate.
/// # Arguments
/// * `referrer` - The referrer.
/// * `tier_id` - The tier level.
- fn set_referrer_tier(ref self: TContractState, referrer: ContractAddress, tier_id: u128);
+ fn set_referrer_tier(ref self: TContractState, referrer: ContractAddress, tier_id: u256);
/// Set the owner for a referral code.
/// # Arguments
@@ -112,7 +111,7 @@ trait IReferralStorage {
/// * `tier_level` - The tier level.
/// # Returns
/// (total_rebate, discount_share).
- fn tiers(self: @TContractState, tier_level: u128) -> ReferralTier;
+ fn tiers(self: @TContractState, tier_level: u256) -> ReferralTier;
}
#[starknet::contract]
@@ -122,7 +121,7 @@ mod ReferralStorage {
// *************************************************************************
// Core lib imports.
- use starknet::{get_caller_address, ContractAddress};
+ use starknet::{get_caller_address, ContractAddress, contract_address_const};
use result::ResultTrait;
// Local imports.
@@ -137,9 +136,9 @@ mod ReferralStorage {
// *************************************************************************
#[storage]
struct Storage {
- referrer_discount_shares: LegacyMap,
- referrer_tiers: LegacyMap,
- tiers: LegacyMap,
+ referrer_discount_shares: LegacyMap,
+ referrer_tiers: LegacyMap,
+ tiers: LegacyMap,
is_handler: LegacyMap,
code_owners: LegacyMap,
trader_referral_codes: LegacyMap,
@@ -151,12 +150,12 @@ mod ReferralStorage {
self.initialize(event_emitter_address);
}
- const BASIS_POINTS: u128 = 10000;
+ const BASIS_POINTS: u256 = 10000;
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl ReferralStorageImpl of super::IReferralStorage {
fn initialize(ref self: ContractState, event_emitter_address: ContractAddress) {
let mut gov_state = Governable::unsafe_new_contract_state();
@@ -171,15 +170,15 @@ mod ReferralStorage {
self.trader_referral_codes.read(account)
}
- fn referrer_discount_shares(self: @ContractState, account: ContractAddress) -> u128 {
+ fn referrer_discount_shares(self: @ContractState, account: ContractAddress) -> u256 {
self.referrer_discount_shares.read(account)
}
- fn referrer_tiers(self: @ContractState, account: ContractAddress) -> u128 {
+ fn referrer_tiers(self: @ContractState, account: ContractAddress) -> u256 {
self.referrer_tiers.read(account)
}
- fn tiers(self: @ContractState, tier_level: u128) -> ReferralTier {
+ fn tiers(self: @ContractState, tier_level: u256) -> ReferralTier {
self.tiers.read(tier_level)
}
@@ -195,7 +194,7 @@ mod ReferralStorage {
}
fn set_tier(
- ref self: ContractState, tier_id: u128, total_rebate: u128, discount_share: u128
+ ref self: ContractState, tier_id: u256, total_rebate: u256, discount_share: u256
) {
let gov_state = Governable::unsafe_new_contract_state();
gov_state.only_gov();
@@ -209,14 +208,14 @@ mod ReferralStorage {
self.event_emitter.read().emit_set_tier(tier_id, total_rebate, discount_share);
}
- fn set_referrer_tier(ref self: ContractState, referrer: ContractAddress, tier_id: u128) {
+ fn set_referrer_tier(ref self: ContractState, referrer: ContractAddress, tier_id: u256) {
let gov_state = Governable::unsafe_new_contract_state();
gov_state.only_gov();
self.referrer_tiers.write(referrer, tier_id);
self.event_emitter.read().emit_set_referrer_tier(referrer, tier_id);
}
- fn set_referrer_discount_share(ref self: ContractState, discount_share: u128) {
+ fn set_referrer_discount_share(ref self: ContractState, discount_share: u256) {
assert(discount_share <= BASIS_POINTS, MockError::INVALID_DISCOUNT_SHARE);
self.referrer_discount_shares.write(get_caller_address(), discount_share);
@@ -240,7 +239,8 @@ mod ReferralStorage {
fn register_code(ref self: ContractState, code: felt252) {
assert(code != 0, MockError::INVALID_CODE);
assert(
- self.code_owners.read(code) == 0.try_into().unwrap(), MockError::CODE_ALREADY_EXISTS
+ self.code_owners.read(code) == contract_address_const::<0>(),
+ MockError::CODE_ALREADY_EXISTS
);
self.code_owners.write(code, get_caller_address());
@@ -270,8 +270,8 @@ mod ReferralStorage {
fn get_trader_referral_info(
self: @ContractState, account: ContractAddress
) -> (felt252, ContractAddress) {
- let mut code: felt252 = self.trader_referral_codes.read(account);
- let mut referrer: ContractAddress = 0.try_into().unwrap();
+ let mut code: felt252 = self.trader_referral_codes(account);
+ let mut referrer = contract_address_const::<0>();
if (code != 0) {
referrer = self.code_owners.read(code);
diff --git a/src/nonce/nonce_utils.cairo b/src/nonce/nonce_utils.cairo
index 08323eb4..c79b2c7b 100644
--- a/src/nonce/nonce_utils.cairo
+++ b/src/nonce/nonce_utils.cairo
@@ -10,8 +10,8 @@ use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait};
/// * `data_store` - The data store to use.
/// # Returns
/// Return the current nonce value.
-fn get_current_nonce(data_store: IDataStoreDispatcher) -> u128 {
- data_store.get_u128(keys::nonce())
+fn get_current_nonce(data_store: IDataStoreDispatcher) -> u256 {
+ data_store.get_u256(keys::nonce())
}
/// Increment the current nonce value.
@@ -19,8 +19,8 @@ fn get_current_nonce(data_store: IDataStoreDispatcher) -> u128 {
/// * `data_store` - The data store to use.
/// # Returns
/// Return the new nonce value.
-fn increment_nonce(data_store: IDataStoreDispatcher) -> u128 {
- data_store.increment_u128(keys::nonce(), 1)
+fn increment_nonce(data_store: IDataStoreDispatcher) -> u256 {
+ data_store.increment_u256(keys::nonce(), 1)
}
/// Creates a felt252 hash using the next nonce. The nonce can also be used directly as a key,
@@ -34,7 +34,7 @@ fn get_next_key(data_store: IDataStoreDispatcher) -> felt252 {
compute_key(data_store.contract_address, nonce)
}
-fn compute_key(data_store_address: ContractAddress, nonce: u128) -> felt252 {
- let data = array![data_store_address.into(), nonce.into()];
+fn compute_key(data_store_address: ContractAddress, nonce: u256) -> felt252 {
+ let data = array![data_store_address.into(), nonce.try_into().expect('u256 into felt failed')];
poseidon_hash_span(data.span())
}
diff --git a/src/oracle/error.cairo b/src/oracle/error.cairo
index 4e1487bb..a3577597 100644
--- a/src/oracle/error.cairo
+++ b/src/oracle/error.cairo
@@ -1,7 +1,9 @@
mod OracleError {
use starknet::ContractAddress;
+ use serde::Serde;
const ALREADY_INITIALIZED: felt252 = 'already_initialized';
+ const EMPTY_ORACLE_BLOCK_NUMBERS: felt252 = 'empty_oracle_block_numbers';
fn NON_EMPTY_TOKENS_WITH_PRICES(data: u32) {
panic(array!['non empty tokens prices', data.into()])
@@ -35,89 +37,137 @@ mod OracleError {
panic(array!['block number not sorted', data_1.into(), data_2.into()])
}
- fn ARRAY_OUT_OF_BOUNDS_FELT252(mut data_1: Span, data_2: u128, msg: felt252) {
+ fn ARRAY_OUT_OF_BOUNDS_FELT252(mut data_1: Span>, data_2: usize, msg: felt252) {
let mut data: Array = array!['array out of bounds felt252'];
let mut length = data_1.len();
- loop {
- if length == 0 {
- break;
- }
- data.append(*data_1.pop_front().unwrap());
- };
+ // TODO add data_1 data to error
data.append(data_2.into());
data.append(msg);
panic(data)
}
- fn ARRAY_OUT_OF_BOUNDS_U128(mut data_1: Span, data_2: u128, msg: felt252) {
- let mut data: Array = array!['array out of bounds u128'];
+ fn ARRAY_OUT_OF_BOUNDS_U256(mut data_1: Span, data_2: u256, msg: felt252) {
+ let mut data: Array = array!['array out of bounds u256'];
let mut length = data_1.len();
loop {
if length == 0 {
break;
}
- data.append((*data_1.pop_front().unwrap()).into());
+ data
+ .append(
+ (*data_1.pop_front().expect('array pop_front failed'))
+ .try_into()
+ .expect('u256 into felt failed')
+ );
};
- data.append(data_2.into());
+ data.append(data_2.try_into().expect('u256 into felt failed'));
data.append(msg);
panic(data)
}
- fn INVALID_SIGNER_MIN_MAX_PRICE(data_1: u128, data_2: u128) {
- panic(array!['invalid med min-max price', data_1.into(), data_2.into()])
+ fn INVALID_SIGNER_MIN_MAX_PRICE(data_1: u256, data_2: u256) {
+ panic(
+ array![
+ 'invalid med min-max price',
+ data_1.try_into().expect('u256 into felt failed'),
+ data_2.try_into().expect('u256 into felt failed')
+ ]
+ )
}
- fn INVALID_MEDIAN_MIN_MAX_PRICE(data_1: u128, data_2: u128) {
- panic(array!['invalid med min-max price', data_1.into(), data_2.into()])
+ fn INVALID_MEDIAN_MIN_MAX_PRICE(data_1: u256, data_2: u256) {
+ panic(
+ array![
+ 'invalid med min-max price',
+ data_1.try_into().expect('u256 into felt failed'),
+ data_2.try_into().expect('u256 into felt failed')
+ ]
+ )
}
fn INVALID_ORACLE_PRICE(data_1: ContractAddress) {
panic(array!['invalid oracle price', data_1.into()])
}
- fn MIN_ORACLE_SIGNERS(data_1: u128, data_2: u128) {
+ fn MIN_ORACLE_SIGNERS(data_1: u256, data_2: u256) {
let mut data: Array = array!['min oracle signers'];
- data.append(data_1.into());
- data.append(data_2.into());
- panic(array!['min oracle signers', data_1.into(), data_2.into()])
+ data.append(data_1.try_into().expect('u256 into felt failed'));
+ data.append(data_2.try_into().expect('u256 into felt failed'));
+ panic(data)
}
- fn MAX_ORACLE_SIGNERS(data_1: u128, data_2: u128) {
- panic(array!['max oracle signers', data_1.into(), data_2.into()])
+ fn MAX_ORACLE_SIGNERS(data_1: u256, data_2: u256) {
+ panic(
+ array![
+ 'max oracle signers',
+ data_1.try_into().expect('u256 into felt failed'),
+ data_2.try_into().expect('u256 into felt failed')
+ ]
+ )
}
- fn MAX_SIGNERS_INDEX(data_1: u128, data_2: u128) {
- panic(array!['max signers index', data_1.into(), data_2.into()])
+ fn MAX_SIGNERS_INDEX(data_1: u256, data_2: u256) {
+ panic(
+ array![
+ 'max signers index',
+ data_1.try_into().expect('u256 into felt failed'),
+ data_2.try_into().expect('u256 into felt failed')
+ ]
+ )
}
- fn EMPTY_SIGNER(data_1: u128) {
- panic(array!['empty signers', data_1.into()])
+ fn EMPTY_SIGNER(data_1: u256) {
+ panic(array!['empty signers', data_1.try_into().expect('u256 into felt failed')])
}
fn MAX_REFPRICE_DEVIATION_EXCEEDED(
- data_1: ContractAddress, data_2: u128, data_3: u128, data_4: u128
+ data_1: ContractAddress, data_2: u256, data_3: u256, data_4: u256
) {
panic(
array![
- 'max refprice deviation', data_1.into(), data_2.into(), data_3.into(), data_4.into()
+ 'max refprice deviation',
+ data_1.into(),
+ data_2.try_into().expect('u256 into felt failed'),
+ data_3.try_into().expect('u256 into felt failed'),
+ data_4.try_into().expect('u256 into felt failed')
]
)
}
- fn INVALID_PRICE_FEED(data_1: ContractAddress, data_2: u128) {
- panic(array!['invalid price feed', data_1.into(), data_2.into()])
+ fn INVALID_PRICE_FEED(data_1: ContractAddress, data_2: u256) {
+ panic(
+ array![
+ 'invalid price feed',
+ data_1.into(),
+ data_2.try_into().expect('u256 into felt failed')
+ ]
+ )
}
fn INVALID_PRIMARY_PRICES_FOR_SIMULATION(data_1: u32, data_2: u32) {
panic(array!['Simulation:invalid prim_prices', data_1.into(), data_2.into()])
}
- fn PRICE_FEED_NOT_UPDATED(data_1: ContractAddress, data_2: u64, data_3: u128) {
- panic(array!['price feed not updated', data_1.into(), data_2.into(), data_3.into()])
+ fn PRICE_FEED_NOT_UPDATED(data_1: ContractAddress, data_2: u64, data_3: u256) {
+ panic(
+ array![
+ 'price feed not updated',
+ data_1.into(),
+ data_2.into(),
+ data_3.try_into().expect('u256 into felt failed')
+ ]
+ )
}
- fn PRICE_ALREADY_SET(data_1: ContractAddress, data_2: u128, data_3: u128) {
- panic(array!['price already set', data_1.into(), data_2.into(), data_3.into()])
+ fn PRICE_ALREADY_SET(data_1: ContractAddress, data_2: u256, data_3: u256) {
+ panic(
+ array![
+ 'price already set',
+ data_1.into(),
+ data_2.try_into().expect('u256 into felt failed'),
+ data_3.try_into().expect('u256 into felt failed')
+ ]
+ )
}
fn EMPTY_PRICE_FEED(data_1: ContractAddress) {
@@ -127,5 +177,90 @@ mod OracleError {
fn END_OF_ORACLE_SIMULATION() {
panic(array!['end of oracle simulation'])
}
-}
+ fn ORACLE_BLOCK_NUMBERS_NOT_WITHIN_RANGE(
+ min_oracle_block_numbers: Span, max_oracle_block_numbers: Span, block_number: u64
+ ) {
+ let mut data: Array = array![];
+ data.append('block number not in range');
+ Serde::serialize(min_oracle_block_numbers.snapshot, ref data);
+ Serde::serialize(max_oracle_block_numbers.snapshot, ref data);
+ data.append(block_number.into());
+ panic(data)
+ }
+
+ fn ORACLE_BLOCK_NUMBERS_ARE_SMALLER_THAN_REQUIRED(
+ min_oracle_block_numbers: Span, block_number: u64
+ ) {
+ let mut data: Array = array![];
+ data.append('block numbers too small');
+ Serde::serialize(min_oracle_block_numbers.snapshot, ref data);
+ data.append(block_number.into());
+ panic(data)
+ }
+
+ fn BLOCK_NUMBER_NOT_WITHIN_RANGE(mut data_1: Span, mut data_2: Span, data_3: u64) {
+ let mut data: Array = array!['block number not within range'];
+ let mut length = data_1.len();
+ loop {
+ if length == 0 {
+ break;
+ }
+ let el = *data_1.pop_front().unwrap();
+ data.append(el.into());
+ };
+ let mut length_2 = data_2.len();
+ loop {
+ if length_2 == 0 {
+ break;
+ }
+ let el = *data_2.pop_front().unwrap();
+ data.append(el.into());
+ };
+ data.append(data_3.into());
+ panic(data)
+ }
+
+ fn EMPTY_COMPACTED_PRICE(data_1: usize) {
+ panic(array!['empty compacted price', data_1.into()])
+ }
+
+ fn EMPTY_COMPACTED_TIMESTAMP(data_1: usize) {
+ panic(array!['empty compacted timestamp', data_1.into()])
+ }
+
+ fn INVALID_SIGNATURE(data_1: felt252, data_2: felt252) {
+ panic(array!['invalid signature', data_1.into(), data_2.into()])
+ }
+
+ fn BLOCK_NUMBERS_ARE_SMALLER_THAN_REQUIRED(mut data_1: Span, data_2: u64) {
+ let mut data: Array = array!['block numbers too small'];
+ let mut length = data_1.len();
+ loop {
+ if length == 0 {
+ break;
+ }
+ let el = *data_1.pop_front().unwrap();
+ data.append(el.into());
+ };
+ data.append(data_2.into());
+ }
+
+ fn MIN_PRICES_NOT_SORTED(token: ContractAddress, min_price: u256, min_price_prev: u256) {
+ let mut data: Array = array![];
+ data.append('min prices not sorted');
+ data.append(token.into());
+ data.append(min_price.try_into().expect('u256 into felt failed'));
+ data.append(min_price_prev.try_into().expect('u256 into felt failed'));
+ panic(data)
+ }
+
+ fn MAX_PRICES_NOT_SORTED(token: ContractAddress, max_price: u256, max_price_prev: u256) {
+ let mut data: Array = array![];
+ data.append('max prices not sorted');
+ data.append(token.into());
+ data.append(max_price.try_into().expect('u256 into felt failed'));
+ data.append(max_price_prev.try_into().expect('u256 into felt failed'));
+ panic(data)
+ }
+}
diff --git a/src/oracle/interfaces/account.cairo b/src/oracle/interfaces/account.cairo
new file mode 100644
index 00000000..651774e2
--- /dev/null
+++ b/src/oracle/interfaces/account.cairo
@@ -0,0 +1,76 @@
+#[starknet::interface]
+trait IAccount {
+ fn __validate_declare__(self: @TContractState, class_hash: felt252) -> felt252;
+ fn __validate_deploy__(
+ self: @TContractState,
+ class_hash: felt252,
+ contract_address_salt: felt252,
+ owner: felt252,
+ guardian: felt252
+ ) -> felt252;
+ // External
+
+ /// @notice Changes the owner
+ /// Must be called by the account and authorised by the owner and a guardian (if guardian is set).
+ /// @param new_owner New owner address
+ /// @param signature_r Signature R from the new owner
+ /// @param signature_S Signature S from the new owner
+ /// Signature is required to prevent changing to an address which is not in control of the user
+ /// Signature is the Signed Message of this hash:
+ /// hash = pedersen(0, (change_owner selector, chainid, contract address, old_owner))
+ fn change_owner(
+ ref self: TContractState, new_owner: felt252, signature_r: felt252, signature_s: felt252
+ );
+
+ /// @notice Changes the guardian
+ /// Must be called by the account and authorised by the owner and a guardian (if guardian is set).
+ /// @param new_guardian The address of the new guardian, or 0 to disable the guardian
+ /// @dev can only be set to 0 if there is no guardian backup set
+ fn change_guardian(ref self: TContractState, new_guardian: felt252);
+
+ /// @notice Changes the backup guardian
+ /// Must be called by the account and authorised by the owner and a guardian (if guardian is set).
+ /// @param new_guardian_backup The address of the new backup guardian, or 0 to disable the backup guardian
+ fn change_guardian_backup(ref self: TContractState, new_guardian_backup: felt252);
+
+ /// @notice Triggers the escape of the owner when it is lost or compromised.
+ /// Must be called by the account and authorised by just a guardian.
+ /// Cannot override an ongoing escape of the guardian.
+ /// @param new_owner The new account owner if the escape completes
+ /// @dev This method assumes that there is a guardian, and that `_newOwner` is not 0.
+ /// This must be guaranteed before calling this method, usually when validating the transaction.
+ fn trigger_escape_owner(ref self: TContractState, new_owner: felt252);
+
+ /// @notice Triggers the escape of the guardian when it is lost or compromised.
+ /// Must be called by the account and authorised by the owner alone.
+ /// Can override an ongoing escape of the owner.
+ /// @param new_guardian The new account guardian if the escape completes
+ /// @dev This method assumes that there is a guardian, and that `new_guardian` can only be 0
+ /// if there is no guardian backup.
+ /// This must be guaranteed before calling this method, usually when validating the transaction
+ fn trigger_escape_guardian(ref self: TContractState, new_guardian: felt252);
+
+ /// @notice Completes the escape and changes the owner after the security period
+ /// Must be called by the account and authorised by just a guardian
+ /// @dev This method assumes that there is a guardian, and that the there is an escape for the owner.
+ /// This must be guaranteed before calling this method, usually when validating the transaction.
+ fn escape_owner(ref self: TContractState);
+
+ /// @notice Completes the escape and changes the guardian after the security period
+ /// Must be called by the account and authorised by just the owner
+ /// @dev This method assumes that there is a guardian, and that the there is an escape for the guardian.
+ /// This must be guaranteed before calling this method. Usually when validating the transaction.
+ fn escape_guardian(ref self: TContractState);
+
+ /// @notice Cancels an ongoing escape if any.
+ /// Must be called by the account and authorised by the owner and a guardian (if guardian is set).
+ fn cancel_escape(ref self: TContractState);
+
+ // Views
+ fn get_owner(self: @TContractState) -> felt252;
+ fn get_guardian(self: @TContractState) -> felt252;
+ fn get_guardian_backup(self: @TContractState) -> felt252;
+ fn get_name(self: @TContractState) -> felt252;
+ fn get_guardian_escape_attempts(self: @TContractState) -> u32;
+ fn get_owner_escape_attempts(self: @TContractState) -> u32;
+}
diff --git a/src/oracle/oracle.cairo b/src/oracle/oracle.cairo
index 6b2c4c55..13330fbe 100644
--- a/src/oracle/oracle.cairo
+++ b/src/oracle/oracle.cairo
@@ -20,6 +20,8 @@ use satoru::oracle::{
oracle_utils::{SetPricesParams, ReportInfo}, error::OracleError,
};
use satoru::price::price::Price;
+use pragma_lib::types::{AggregationMode, DataType, PragmaPricesResponse};
+
// *************************************************************************
// Interface of the `Oracle` contract.
@@ -103,7 +105,7 @@ trait IOracle {
/// The stable price of a token.
fn get_stable_price(
self: @TContractState, data_store: IDataStoreDispatcher, token: ContractAddress
- ) -> u128;
+ ) -> u256;
/// Get the multiplier value to convert the external price feed price to the price of 1 unit of the token
/// represented with 30 decimals.
@@ -120,15 +122,17 @@ trait IOracle {
/// The price feed multiplier.
fn get_price_feed_multiplier(
self: @TContractState, data_store: IDataStoreDispatcher, token: ContractAddress,
- ) -> u128;
+ ) -> u256;
- /// Validate prices in `params` for oracles.
+ /// Validate prices in `params` for oracles. TODO implement price validations
/// # Arguments
/// * `data_store` - The `DataStore` contract dispatcher.
/// * `params` - The parameters used to set prices in oracle.
- fn validate_prices(
- self: @TContractState, data_store: IDataStoreDispatcher, params: SetPricesParams,
- ) -> Array;
+ // fn validate_prices(
+ // self: @TContractState, data_store: IDataStoreDispatcher, params: SetPricesParams,
+ // ) -> Array;
+
+ fn get_asset_price_median(self: @TContractState, asset: DataType) -> PragmaPricesResponse;
}
/// A price that has been validated in validate_prices().
@@ -137,9 +141,9 @@ struct ValidatedPrice {
/// The token to validate the price for.
token: ContractAddress,
/// The min price of the token.
- min: u128,
+ min: u256,
/// The max price of the token.
- max: u128,
+ max: u256,
/// The timestamp of the price validated.
timestamp: u64,
min_block_number: u64,
@@ -155,7 +159,7 @@ struct SetPricesCache {
/// The max allowed age of price values.
max_price_age: u64,
/// The max ref_price deviation factor allowed.
- max_ref_price_deviation_factor: u128,
+ max_ref_price_deviation_factor: u256,
/// The previous oracle block number of the loop.
prev_min_oracle_block_number: u64,
// The prices that have been validated to set.
@@ -165,23 +169,23 @@ struct SetPricesCache {
/// Struct used in validate_prices as an inner cache.
#[derive(Default, Drop)]
struct SetPricesInnerCache {
- /// The current price index to retrieve from compactedMinPrices and compactedMaxPrices
- /// to construct the minPrices and maxPrices array.
- price_index: u128,
+ /// The current price index to retrieve from compacted_min_prices and compacted_max_prices
+ /// to construct the min_prices and max_prices array.
+ price_index: usize,
/// The current signature index to retrieve from the signatures array.
- signature_index: u128,
+ signature_index: usize,
/// The index of the min price in min_prices for the current signer.
- min_price_index: u128,
+ min_price_index: u256,
/// The index of the max price in max_prices for the current signer.
- max_price_index: u128,
+ max_price_index: u256,
/// The min prices.
- min_prices: Array,
+ min_prices: Array,
/// The max prices.
- max_prices: Array,
- /// The min price index using U128Mask.
- min_price_index_mask: u128,
- /// The max price index using U128Mask.
- max_price_index_mask: u128,
+ max_prices: Array,
+ /// The min price index using U256Mask.
+ min_price_index_mask: u256,
+ /// The max price index using U256Mask.
+ max_price_index_mask: u256,
}
#[starknet::contract]
@@ -191,8 +195,11 @@ mod Oracle {
// *************************************************************************
// Core lib imports.
+ use core::traits::Into;
+ use core::traits::TryInto;
use core::zeroable::Zeroable;
use starknet::ContractAddress;
+ use starknet::contract_address_const;
use starknet::info::{get_block_timestamp, get_block_number};
use starknet::syscalls::get_block_hash_syscall;
use starknet::SyscallResultTrait;
@@ -202,7 +209,6 @@ mod Oracle {
use alexandria_sorting::merge_sort;
use alexandria_storage::list::{ListTrait, List};
use poseidon::poseidon_hash_span;
-
// Local imports.
use satoru::data::{data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait}, keys};
use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait};
@@ -210,16 +216,16 @@ mod Oracle {
use satoru::oracle::{
oracle_store::{IOracleStoreDispatcher, IOracleStoreDispatcherTrait}, oracle_utils,
oracle_utils::{SetPricesParams, ReportInfo}, error::OracleError,
- price_feed::{
- IPriceFeedDispatcher, IPriceFeedDispatcherTrait, DataType, PragmaPricesResponse,
- }
};
use satoru::role::role_module::{
IRoleModule, RoleModule
}; //::role_store::IInternalContractMemberStateTrait as RoleModuleStateTrait;
use satoru::role::role_store::{IRoleStoreDispatcher, IRoleStoreDispatcherTrait};
use satoru::utils::{arrays, arrays::pow, bits, calc, precision};
- use satoru::utils::u128_mask::{Mask, MaskTrait, validate_unique_and_set_index};
+ use satoru::utils::u256_mask::{Mask, MaskTrait, validate_unique_and_set_index};
+
+ use pragma_lib::abi::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait};
+ use pragma_lib::types::{AggregationMode, DataType, PragmaPricesResponse};
use super::{IOracle, SetPricesCache, SetPricesInnerCache, ValidatedPrice};
@@ -227,11 +233,11 @@ mod Oracle {
// *************************************************************************
// CONSTANTS
// *************************************************************************
- const SIGNER_INDEX_LENGTH: u128 = 16;
+ const SIGNER_INDEX_LENGTH: u256 = 16;
// subtract 1 as the first slot is used to store number of signers
- const MAX_SIGNERS: u128 = 15; //128 / SIGNER_INDEX_LENGTH - 1;
- // signer indexes are recorded in a signerIndexFlags uint128 value to check for uniqueness
- const MAX_SIGNER_INDEX: u128 = 128;
+ const MAX_SIGNERS: u256 = 15; //256 / SIGNER_INDEX_LENGTH - 1;
+ // signer indexes are recorded in a signerIndexFlags uint256 value to check for uniqueness
+ const MAX_SIGNER_INDEX: u256 = 256;
// *************************************************************************
@@ -244,7 +250,7 @@ mod Oracle {
/// Interface to interact with the `OracleStore` contract.
oracle_store: IOracleStoreDispatcher,
/// Interface to interact with the Pragma Oracle.
- price_feed: IPriceFeedDispatcher,
+ price_feed: IPragmaABIDispatcher,
/// List of Prices related to a token.
tokens_with_prices: List,
/// Mapping between tokens and prices.
@@ -269,11 +275,10 @@ mod Oracle {
self.initialize(role_store_address, oracle_store_address, pragma_address);
}
-
// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
- #[external(v0)]
+ #[abi(embed_v0)]
impl OracleImpl of super::IOracle {
fn initialize(
ref self: ContractState,
@@ -289,7 +294,7 @@ mod Oracle {
self
.oracle_store
.write(IOracleStoreDispatcher { contract_address: oracle_store_address });
- self.price_feed.write(IPriceFeedDispatcher { contract_address: pragma_address });
+ self.price_feed.write(IPragmaABIDispatcher { contract_address: pragma_address });
}
fn set_prices(
@@ -300,20 +305,33 @@ mod Oracle {
) {
let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
IRoleModule::only_controller(@state);
-
let tokens_with_prices_len = self.tokens_with_prices.read().len();
if !tokens_with_prices_len.is_zero() {
OracleError::NON_EMPTY_TOKENS_WITH_PRICES(tokens_with_prices_len);
};
- self.set_prices_from_price_feeds(data_store, event_emitter, @params.price_feed_tokens);
+ // self.set_prices_from_price_feeds(data_store, event_emitter, @params.price_feed_tokens); TODO uncomment
// it is possible for transactions to be executed using just params.priceFeedTokens
// in this case if params.tokens is empty, the function can return
if params.tokens.len().is_zero() {
return;
}
-
- self.set_prices_(data_store, event_emitter, params);
+ // only for testing
+ // TODO Find how to handle decimals, example ETH price 3453.92399931123
+ let mut i = 0;
+ loop {
+ if i == params.tokens.len() {
+ break;
+ }
+ let token = *params.tokens.at(i);
+ let price = Price {
+ min: *params.compacted_max_prices.at(i), max: *params.compacted_max_prices.at(i)
+ };
+ self.set_primary_price_(token, price);
+ i += 1;
+ };
+ // end for testing
+ // self.set_prices_(data_store, event_emitter, params); TODO uncomment
}
// Set the primary price
@@ -329,17 +347,23 @@ mod Oracle {
fn clear_all_prices(ref self: ContractState) {
let state: RoleModule::ContractState = RoleModule::unsafe_new_contract_state();
IRoleModule::only_controller(@state);
- let mut len = 0;
loop {
- if len == self.tokens_with_prices.read().len() {
+ if self.tokens_with_prices.read().len() == Zeroable::zero() {
break;
}
- let token = self.tokens_with_prices.read().get(len).unwrap();
+ let token = self.tokens_with_prices.read().get(0).expect('array get failed');
self.remove_primary_price(token);
- len += 1;
- }
+ };
}
+ fn get_asset_price_median(self: @ContractState, asset: DataType) -> PragmaPricesResponse {
+ self.price_feed.read().get_data(asset, AggregationMode::Median(()))
+ }
+ //USAGE/
+ // let KEY :felt252 = 18669995996566340; // felt252 conversion of "BTC/USD", can also write const KEY : felt252 = 'BTC/USD';
+ // Sepolia contract address : 0x36031daa264c24520b11d93af622c848b2499b66b41d611bac95e13cfca131a
+ // let oracle_address : ContractAddress = contract_address_const::<0x06df335982dddce41008e4c03f2546fa27276567b5274c7d0c1262f3c2b5d167>();
+ // let price = get_asset_price_median(DataType::SpotEntry(KEY));
fn get_tokens_with_prices_count(self: @ContractState) -> u32 {
let token_with_prices = self.tokens_with_prices.read();
@@ -350,7 +374,7 @@ mod Oracle {
if i == tokens_with_prices_len {
break;
}
- if !token_with_prices.get(i).unwrap().is_zero() {
+ if !token_with_prices.get(i).expect('array get failed').is_zero() {
count += 1;
}
i += 1;
@@ -396,26 +420,25 @@ mod Oracle {
fn get_stable_price(
self: @ContractState, data_store: IDataStoreDispatcher, token: ContractAddress
- ) -> u128 {
- data_store.get_u128(keys::stable_price_key(token))
+ ) -> u256 {
+ data_store.get_u256(keys::stable_price_key(token))
}
fn get_price_feed_multiplier(
self: @ContractState, data_store: IDataStoreDispatcher, token: ContractAddress,
- ) -> u128 {
- let multiplier = data_store.get_u128(keys::price_feed_multiplier_key(token));
+ ) -> u256 {
+ let multiplier = data_store.get_u256(keys::price_feed_multiplier_key(token));
if multiplier.is_zero() {
OracleError::EMPTY_PRICE_FEED_MULTIPLIER();
}
multiplier
}
-
- fn validate_prices(
- self: @ContractState, data_store: IDataStoreDispatcher, params: SetPricesParams,
- ) -> Array