diff --git a/.gitignore b/.gitignore
index bddaee85..17eaa901 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
.DS_Store
/emitter/.DS_Store
+test_snapshots/
+
# JS
*/node_modules
local.*
diff --git a/Cargo.lock b/Cargo.lock
index 37485d83..11068a87 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
-version = "0.20.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
@@ -34,9 +34,9 @@ dependencies = [
[[package]]
name = "arbitrary"
-version = "1.3.0"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
+checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
@@ -52,17 +52,18 @@ name = "backstop"
version = "0.0.1"
dependencies = [
"cast",
- "fixed-point-math",
+ "emitter",
"mock-pool-factory",
"sep-41-token",
+ "soroban-fixed-point-math",
"soroban-sdk",
]
[[package]]
name = "backtrace"
-version = "0.3.68"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
@@ -234,9 +235,9 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
-version = "4.0.0"
+version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2"
+checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -307,9 +308,9 @@ dependencies = [
[[package]]
name = "derive_arbitrary"
-version = "1.3.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8"
+checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
@@ -401,16 +402,27 @@ dependencies = [
name = "emitter"
version = "0.0.1"
dependencies = [
- "backstop",
"sep-41-token",
"soroban-sdk",
]
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "escape-bytes"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2"
+
[[package]]
name = "ethnum"
-version = "1.3.2"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0198b9d0078e0f30dedc7acbb21c974e838fc8fae3ee170128658a98cb2c1c04"
+checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c"
[[package]]
name = "ff"
@@ -424,15 +436,9 @@ dependencies = [
[[package]]
name = "fiat-crypto"
-version = "0.1.20"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
-
-[[package]]
-name = "fixed-point-math"
-version = "0.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d8c494ccd0b270d97dc51d5f0de703b9d18a489c26f0328e409f6feba55a640"
+checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7"
[[package]]
name = "fnv"
@@ -464,9 +470,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"js-sys",
@@ -477,9 +483,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.27.3"
+version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "group"
@@ -498,6 +504,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
[[package]]
name = "hex"
version = "0.4.3"
@@ -507,6 +519,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "hex-literal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
+
[[package]]
name = "hmac"
version = "0.12.1"
@@ -552,7 +570,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
"serde",
]
@@ -564,9 +593,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590"
[[package]]
name = "itertools"
-version = "0.10.5"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
@@ -611,9 +640,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.147"
+version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libm"
@@ -664,9 +693,9 @@ dependencies = [
[[package]]
name = "num-derive"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
+checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712"
dependencies = [
"proc-macro2",
"quote",
@@ -685,18 +714,18 @@ dependencies = [
[[package]]
name = "num-traits"
-version = "0.2.15"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "object"
-version = "0.31.1"
+version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
@@ -735,10 +764,11 @@ version = "0.0.1"
dependencies = [
"backstop",
"cast",
- "fixed-point-math",
+ "emitter",
"mock-pool-factory",
"sep-40-oracle",
"sep-41-token",
+ "soroban-fixed-point-math",
"soroban-sdk",
]
@@ -768,18 +798,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.31"
+version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@@ -843,7 +873,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
]
[[package]]
@@ -908,36 +938,36 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "sep-40-oracle"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa589e8db60e397c7a7af90908eab64ca46cc5628957a554a24efb36235b34d2"
+checksum = "ea393e9867e2a2a73a32be6e7a7b81c78ee3779dc1cdf7b2343b23a16739a181"
dependencies = [
"soroban-sdk",
]
[[package]]
name = "sep-41-token"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0edb6a114daf783364bf705d27f97a4f49ae858518eb46d46e4161cd75b9678"
+checksum = "8832c57dd6d2ad1d31f9ac8434bd84677ab4f7ca0e2369fd57df49f42f2567ff"
dependencies = [
"soroban-sdk",
]
[[package]]
name = "serde"
-version = "1.0.171"
+version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
+checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.171"
+version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
+checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
@@ -946,9 +976,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.103"
+version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
@@ -957,14 +987,15 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "3.1.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3"
+checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [
"base64 0.21.2",
"chrono",
"hex",
- "indexmap",
+ "indexmap 1.9.3",
+ "indexmap 2.1.0",
"serde",
"serde_json",
"serde_with_macros",
@@ -973,9 +1004,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.1.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65"
+checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [
"darling",
"proc-macro2",
@@ -985,9 +1016,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.7"
+version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -1020,11 +1051,23 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
+[[package]]
+name = "soroban-builtin-sdk-macros"
+version = "20.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42487d6b0268748f753feeb579c6f7908dbb002faf20b703e6a7185b12f0527"
+dependencies = [
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "soroban-env-common"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2508a41765935d3bef43b2264667c4603725cf7ddd851321f1dc2b3bca8bb88"
+checksum = "5bb493483fa3e3ebfb4c081472495d14b0abcfbe04ba142a56ff63056cc62700"
dependencies = [
"arbitrary",
"crate-git-revision",
@@ -1040,9 +1083,9 @@ dependencies = [
[[package]]
name = "soroban-env-guest"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b41f1b3ebb747487ff9920822112a5816030e053734ed63c05f1a7db476f2768"
+checksum = "3f31a738ef5faf4084c4b1824a8e3f93dfff0261a3909e86060f818e728479a3"
dependencies = [
"soroban-env-common",
"static_assertions",
@@ -1050,13 +1093,16 @@ dependencies = [
[[package]]
name = "soroban-env-host"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "347fc729270de2fc8e312ba1872ef90fdc8dfcd0dacdd07a3bb7a038c41ea6d6"
+checksum = "bdd1172a76c0bc2ce67ec7f28ca37dddbe9fefabe583f80434f5f60aaee3547e"
dependencies = [
"backtrace",
+ "curve25519-dalek",
"ed25519-dalek",
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
+ "hex-literal",
+ "hmac",
"k256",
"num-derive",
"num-integer",
@@ -1065,8 +1111,8 @@ dependencies = [
"rand_chacha 0.3.1",
"sha2",
"sha3",
+ "soroban-builtin-sdk-macros",
"soroban-env-common",
- "soroban-native-sdk-macros",
"soroban-wasmi",
"static_assertions",
"stellar-strkey",
@@ -1074,9 +1120,9 @@ dependencies = [
[[package]]
name = "soroban-env-macros"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f16b7a75d77ae47143a07f92a35661c21e965f63bb4362d8491188a993687745"
+checksum = "5c0536648cea69ab3bae1801d35f92c0a31e7449cd2c7d14a18fb5e413f43279"
dependencies = [
"itertools",
"proc-macro2",
@@ -1087,42 +1133,42 @@ dependencies = [
"syn",
]
+[[package]]
+name = "soroban-fixed-point-math"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "230e5902daf9de6e7591aa7864dcf763ff96914a4460a0294a5dfd62b3181e0f"
+dependencies = [
+ "soroban-sdk",
+]
+
[[package]]
name = "soroban-ledger-snapshot"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d202c5870aeec1cb97bfd06a94b8fe691c513ba6da8638deb07d8660e90056ba"
+checksum = "37960eec21d7dc5dbd976fa16e38c056429663a89243798486b07afbb263c9b5"
dependencies = [
"serde",
"serde_json",
+ "serde_with",
"soroban-env-common",
"soroban-env-host",
"thiserror",
]
-[[package]]
-name = "soroban-native-sdk-macros"
-version = "20.0.0-rc2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe8cf96e5c9308347bc6fa0735d0591475a20b43ed00f96ad2df623bbe9c1e88"
-dependencies = [
- "itertools",
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "soroban-sdk"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d771d43a66ba0df14ff28ac1b37a6568da00afa12f28273a67fe92853ab28f8"
+checksum = "f08e1fdb18dbee88160ea6640962faf021a49f22eb1bd212c4d8b0cef32c582c"
dependencies = [
"arbitrary",
"bytes-lit",
"ctor",
"ed25519-dalek",
"rand 0.8.5",
+ "serde",
+ "serde_json",
"soroban-env-guest",
"soroban-env-host",
"soroban-ledger-snapshot",
@@ -1132,9 +1178,9 @@ dependencies = [
[[package]]
name = "soroban-sdk-macros"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf5a6dd2e08217fdd75f3f849256dda2614badda9095df233a47c7c8f9783493"
+checksum = "6c5cae44f304f2fd32f9cfa9a31a9b58eb1c10aa07a7d5b591921cf7fa649e44"
dependencies = [
"crate-git-revision",
"darling",
@@ -1152,9 +1198,9 @@ dependencies = [
[[package]]
name = "soroban-spec"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e2a55aab81d7cd1df66f85de3d815fb08fc5fa412270dc374e031e27528c711"
+checksum = "7539cfa0abe36f3d33c49fe1253f6b652c91c9a9841fe83dedc1799b7f4bb55f"
dependencies = [
"base64 0.13.1",
"stellar-xdr",
@@ -1164,9 +1210,9 @@ dependencies = [
[[package]]
name = "soroban-spec-rust"
-version = "20.0.0-rc2"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bcfa549d3362e6eafa3a51ad29d571f3dbae2cb9fe33d9f94c00a9f742f71df"
+checksum = "eb6189ef3ede0061db14b0cf9fa2692a2cb6c6e8d941689f0c9ca82b68c47ab2"
dependencies = [
"prettyplease",
"proc-macro2",
@@ -1180,9 +1226,9 @@ dependencies = [
[[package]]
name = "soroban-wasmi"
-version = "0.31.0-soroban1"
+version = "0.31.1-soroban.20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6e3e79c1f227ec98ea1e8fbf43d0267b9ca748616c9c8c0162fa2a8ca4d5d2"
+checksum = "c1aaa682a67cbd2173f1d60cb1e7b951d490d7c4e0b7b6f5387cbb952e963c46"
dependencies = [
"smallvec",
"spin",
@@ -1215,26 +1261,29 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stellar-strkey"
-version = "0.0.7"
+version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c0689070126ca7f2effc2c5726584446db52190f0cef043c02eb4040a711c11"
+checksum = "12d2bf45e114117ea91d820a846fd1afbe3ba7d717988fee094ce8227a3bf8bd"
dependencies = [
"base32",
+ "crate-git-revision",
"thiserror",
]
[[package]]
name = "stellar-xdr"
-version = "20.0.0-rc1"
+version = "20.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e09a3734914a7427dbcd4f06b6dcd2b1cf38e934202f6abe4d73658f718b6113"
+checksum = "9595b775539e475da4179fa46212b11e4575f526d57b13308989a8c1dd59238c"
dependencies = [
"arbitrary",
"base64 0.13.1",
"crate-git-revision",
+ "escape-bytes",
"hex",
"serde",
"serde_with",
+ "stellar-strkey",
]
[[package]]
@@ -1251,9 +1300,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
-version = "2.0.26"
+version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
@@ -1267,13 +1316,13 @@ dependencies = [
"backstop",
"cast",
"emitter",
- "fixed-point-math",
"mock-pool-factory",
"pool",
"pool-factory",
"rand 0.7.3",
"sep-40-oracle",
"sep-41-token",
+ "soroban-fixed-point-math",
"soroban-sdk",
]
@@ -1432,7 +1481,7 @@ version = "0.88.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e"
dependencies = [
- "indexmap",
+ "indexmap 1.9.3",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index f018e664..7bdd0f10 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,20 +26,20 @@ codegen-units = 1
lto = true
[workspace.dependencies.soroban-sdk]
-version = "20.0.0-rc2"
+version = "20.0.0"
-[workspace.dependencies.fixed-point-math]
-version = "0.0.2"
+[workspace.dependencies.soroban-fixed-point-math]
+version = "1.0.0"
[workspace.dependencies.cast]
version = "0.3.0"
default-features = false
[workspace.dependencies.sep-40-oracle]
-version = "0.1.1"
+version = "0.2.0"
[workspace.dependencies.sep-41-token]
-version = "0.2.1"
+version = "0.3.0"
[workspace.dependencies.blend-interfaces]
path = "./blend-interfaces"
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 6a166833..83dc0152 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,9 @@ test: build
cargo test --all --tests
build:
+ cargo rustc --manifest-path=emitter/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=pool-factory/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=backstop/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
- cargo rustc --manifest-path=emitter/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
cargo rustc --manifest-path=pool/Cargo.toml --crate-type=cdylib --target=wasm32-unknown-unknown --release
mkdir -p target/wasm32-unknown-unknown/optimized
soroban contract optimize \
diff --git a/backstop/Cargo.toml b/backstop/Cargo.toml
index 32ec4852..64ee986f 100644
--- a/backstop/Cargo.toml
+++ b/backstop/Cargo.toml
@@ -17,11 +17,12 @@ testutils = [
[dependencies]
soroban-sdk = { workspace = true }
-fixed-point-math = { workspace = true }
+soroban-fixed-point-math = { workspace = true }
cast = { workspace = true }
sep-41-token = { workspace = true }
[dev_dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
mock-pool-factory = { path = "../mocks/mock-pool-factory", features = ["testutils"] }
+emitter = { path = "../emitter", features = ["testutils"] }
sep-41-token = { workspace = true, features = ["testutils"] }
diff --git a/backstop/src/backstop/deposit.rs b/backstop/src/backstop/deposit.rs
index ac81c3a4..482cea65 100644
--- a/backstop/src/backstop/deposit.rs
+++ b/backstop/src/backstop/deposit.rs
@@ -2,10 +2,13 @@ use crate::{contract::require_nonnegative, emissions, storage};
use sep_41_token::TokenClient;
use soroban_sdk::{Address, Env};
+use super::require_is_from_pool_factory;
+
/// Perform a deposit into the backstop module
pub fn execute_deposit(e: &Env, from: &Address, pool_address: &Address, amount: i128) -> i128 {
require_nonnegative(e, amount);
let mut pool_balance = storage::get_pool_balance(e, pool_address);
+ require_is_from_pool_factory(e, pool_address, pool_balance.shares);
let mut user_balance = storage::get_user_balance(e, pool_address, from);
emissions::update_emissions(e, pool_address, &pool_balance, from, &user_balance, false);
@@ -29,7 +32,7 @@ mod tests {
use crate::{
backstop::execute_donate,
- testutils::{create_backstop, create_backstop_token},
+ testutils::{create_backstop, create_backstop_token, create_mock_pool_factory},
};
use super::*;
@@ -41,16 +44,20 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
- let pool_0_id = Address::random(&e);
- let pool_1_id = Address::random(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
+ let pool_0_id = Address::generate(&e);
+ let pool_1_id = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
backstop_token_client.mint(&frodo, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+ mock_pool_factory_client.set_pool(&pool_1_id);
+
// initialize pool 0 with funds + some profit
e.as_contract(&backstop_address, || {
execute_deposit(&e, &frodo, &pool_0_id, 25_0000000);
@@ -94,13 +101,16 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_0_id, 100_0000001);
@@ -116,15 +126,39 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_0_id, -100);
});
}
+
+ #[test]
+ #[should_panic(expected = "Error(Contract, #10)")]
+ fn text_execute_deposit_not_pool() {
+ let e = Env::default();
+ e.mock_all_auths_allowing_non_root_auth();
+
+ let backstop_address = create_backstop(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+
+ let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
+ backstop_token_client.mint(&samwise, &100_0000000);
+
+ create_mock_pool_factory(&e, &backstop_address);
+
+ e.as_contract(&backstop_address, || {
+ execute_deposit(&e, &samwise, &pool_0_id, 100);
+ });
+ }
}
diff --git a/backstop/src/backstop/fund_management.rs b/backstop/src/backstop/fund_management.rs
index 4bafa128..148b0598 100644
--- a/backstop/src/backstop/fund_management.rs
+++ b/backstop/src/backstop/fund_management.rs
@@ -1,8 +1,8 @@
use crate::{
constants::SCALAR_7, contract::require_nonnegative, dependencies::CometClient, storage,
};
-use fixed_point_math::FixedPoint;
use sep_41_token::TokenClient;
+use soroban_fixed_point_math::FixedPoint;
use soroban_sdk::{unwrap::UnwrapOptimized, Address, Env};
use super::require_is_from_pool_factory;
@@ -10,7 +10,6 @@ use super::require_is_from_pool_factory;
/// Perform a draw from a pool's backstop
pub fn execute_draw(e: &Env, pool_address: &Address, amount: i128, to: &Address) {
require_nonnegative(e, amount);
- require_is_from_pool_factory(e, pool_address);
let mut pool_balance = storage::get_pool_balance(e, pool_address);
@@ -25,10 +24,12 @@ pub fn execute_draw(e: &Env, pool_address: &Address, amount: i128, to: &Address)
pub fn execute_donate(e: &Env, from: &Address, pool_address: &Address, amount: i128) {
require_nonnegative(e, amount);
+ let mut pool_balance = storage::get_pool_balance(e, pool_address);
+ require_is_from_pool_factory(e, pool_address, pool_balance.shares);
+
let backstop_token = TokenClient::new(e, &storage::get_backstop_token(e));
backstop_token.transfer(from, &e.current_contract_address(), &amount);
- let mut pool_balance = storage::get_pool_balance(e, pool_address);
pool_balance.deposit(amount, 0);
storage::set_pool_balance(e, pool_address, &pool_balance);
}
@@ -37,10 +38,12 @@ pub fn execute_donate(e: &Env, from: &Address, pool_address: &Address, amount: i
pub fn execute_donate_usdc(e: &Env, from: &Address, pool_address: &Address, amount: i128) {
require_nonnegative(e, amount);
+ let mut pool_usdc = storage::get_pool_usdc(e, pool_address);
+ require_is_from_pool_factory(e, pool_address, pool_usdc);
+
let usdc_token = TokenClient::new(e, &storage::get_usdc_token(e));
usdc_token.transfer(from, &e.current_contract_address(), &amount);
- let mut pool_usdc = storage::get_pool_usdc(e, pool_address);
pool_usdc += amount;
storage::set_pool_usdc(e, pool_address, &pool_usdc);
}
@@ -113,15 +116,18 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
backstop_token_client.mint(&frodo, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
// initialize pool 0 with funds
e.as_contract(&backstop_id, || {
execute_deposit(&e, &frodo, &pool_0_id, 25_0000000);
@@ -144,15 +150,18 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
backstop_token_client.mint(&frodo, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
// initialize pool 0 with funds
e.as_contract(&backstop_id, || {
execute_deposit(&e, &frodo, &pool_0_id, 25_0000000);
@@ -163,6 +172,30 @@ mod tests {
});
}
+ #[test]
+ #[should_panic(expected = "Error(Contract, #10)")]
+ fn test_execute_donate_not_pool() {
+ let e = Env::default();
+ e.mock_all_auths_allowing_non_root_auth();
+ e.budget().reset_unlimited();
+
+ let backstop_id = create_backstop(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
+
+ let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
+ backstop_token_client.mint(&samwise, &100_0000000);
+ backstop_token_client.mint(&frodo, &100_0000000);
+
+ create_mock_pool_factory(&e, &backstop_id);
+
+ e.as_contract(&backstop_id, || {
+ execute_donate(&e, &samwise, &pool_0_id, 30_0000000);
+ });
+ }
+
#[test]
fn test_execute_draw() {
let e = Env::default();
@@ -170,10 +203,10 @@ mod tests {
e.budget().reset_unlimited();
let backstop_address = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&frodo, &100_0000000);
@@ -197,36 +230,6 @@ mod tests {
});
}
- #[test]
- #[should_panic(expected = "Error(Contract, #10)")]
- fn test_execute_draw_requires_pool_factory_verification() {
- let e = Env::default();
- e.mock_all_auths_allowing_non_root_auth();
- e.budget().reset_unlimited();
-
- let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let pool_bad_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
-
- let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
- backstop_token_client.mint(&frodo, &100_0000000);
-
- let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
- mock_pool_factory_client.set_pool(&pool_0_id);
-
- // initialize pool 0 with funds
- e.as_contract(&backstop_id, || {
- execute_deposit(&e, &frodo, &pool_0_id, 50_0000000);
- });
-
- e.as_contract(&backstop_id, || {
- execute_draw(&e, &pool_bad_id, 30_0000000, &samwise);
- });
- }
-
#[test]
#[should_panic(expected = "Error(Contract, #6)")]
fn test_execute_draw_only_can_take_from_pool() {
@@ -235,17 +238,18 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let pool_1_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let pool_1_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
backstop_token_client.mint(&frodo, &100_0000000);
let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
mock_pool_factory_client.set_pool(&pool_0_id);
+ mock_pool_factory_client.set_pool(&pool_1_id);
// initialize pool 0 with funds
e.as_contract(&backstop_id, || {
@@ -266,10 +270,10 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_id, &bombadil);
backstop_token_client.mint(&frodo, &100_0000000);
@@ -294,15 +298,18 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, usdc_token_client) = create_usdc_token(&e, &backstop_id, &bombadil);
usdc_token_client.mint(&samwise, &100_0000000);
usdc_token_client.mint(&frodo, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
e.as_contract(&backstop_id, || {
execute_donate_usdc(&e, &samwise, &pool_0_id, 30_0000000);
let new_pool_usdc = storage::get_pool_usdc(&e, &pool_0_id);
@@ -326,18 +333,43 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, usdc_token_client) = create_usdc_token(&e, &backstop_id, &bombadil);
usdc_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
e.as_contract(&backstop_id, || {
execute_donate_usdc(&e, &samwise, &pool_0_id, -30_0000000);
});
}
+ #[test]
+ #[should_panic(expected = "Error(Contract, #10)")]
+ fn test_execute_donate_usdc_not_pool() {
+ let e = Env::default();
+ e.mock_all_auths_allowing_non_root_auth();
+ e.budget().reset_unlimited();
+
+ let backstop_id = create_backstop(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+
+ let (_, usdc_token_client) = create_usdc_token(&e, &backstop_id, &bombadil);
+ usdc_token_client.mint(&samwise, &100_0000000);
+
+ create_mock_pool_factory(&e, &backstop_id);
+
+ e.as_contract(&backstop_id, || {
+ execute_donate_usdc(&e, &samwise, &pool_0_id, 30_0000000);
+ });
+ }
+
#[test]
fn test_execute_gulp_usdc() {
let e = Env::default();
@@ -345,9 +377,9 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let pool_0_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_0_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (usdc_token, usdc_token_client) = create_usdc_token(&e, &backstop_id, &bombadil);
usdc_token_client.mint(&samwise, &100_0000000);
@@ -355,6 +387,9 @@ mod tests {
let (blnd_token, blnd_token_client) = create_blnd_token(&e, &backstop_id, &bombadil);
blnd_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_id);
+ mock_pool_factory_client.set_pool(&pool_0_id);
+
let (comet_id, comet_client) =
create_comet_lp_pool(&e, &bombadil, &blnd_token, &usdc_token);
@@ -389,8 +424,8 @@ mod tests {
e.budget().reset_unlimited();
let backstop_id = create_backstop(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (usdc_token, usdc_token_client) = create_usdc_token(&e, &backstop_id, &bombadil);
usdc_token_client.mint(&samwise, &100_0000000);
diff --git a/backstop/src/backstop/mod.rs b/backstop/src/backstop/mod.rs
index 1c9ac818..87fbc736 100644
--- a/backstop/src/backstop/mod.rs
+++ b/backstop/src/backstop/mod.rs
@@ -12,7 +12,8 @@ pub use withdrawal::{execute_dequeue_withdrawal, execute_queue_withdrawal, execu
mod pool;
pub use pool::{
- load_pool_backstop_data, require_is_from_pool_factory, PoolBackstopData, PoolBalance,
+ load_pool_backstop_data, require_is_from_pool_factory, require_pool_above_threshold,
+ PoolBackstopData, PoolBalance,
};
mod user;
diff --git a/backstop/src/backstop/pool.rs b/backstop/src/backstop/pool.rs
index c23a1a74..82b7d0aa 100644
--- a/backstop/src/backstop/pool.rs
+++ b/backstop/src/backstop/pool.rs
@@ -1,4 +1,4 @@
-use fixed_point_math::FixedPoint;
+use soroban_fixed_point_math::FixedPoint;
use soroban_sdk::{contracttype, panic_with_error, unwrap::UnwrapOptimized, Address, Env};
use crate::{constants::SCALAR_7, dependencies::PoolFactoryClient, errors::BackstopError, storage};
@@ -38,16 +38,57 @@ pub fn load_pool_backstop_data(e: &Env, address: &Address) -> PoolBackstopData {
}
}
-/// Verify the pool address was deployed by the Pool Factory
+/// Verify the pool address was deployed by the Pool Factory.
///
-/// Panics if the pool address cannot be verified
-pub fn require_is_from_pool_factory(e: &Env, address: &Address) {
- let pool_factory_client = PoolFactoryClient::new(e, &storage::get_pool_factory(e));
- if !pool_factory_client.is_pool(address) {
- panic_with_error!(e, BackstopError::NotPool);
+/// If the pool has an outstanding balance, it is assumed that it was verified before.
+///
+/// ### Arguments
+/// * `address` - The pool address to verify
+/// * `balance` - The balance of the pool. A balance of 0 indicates the pool has not been initialized.
+///
+/// ### Panics
+/// If the pool address cannot be verified
+pub fn require_is_from_pool_factory(e: &Env, address: &Address, balance: i128) {
+ if balance == 0 {
+ let pool_factory_client = PoolFactoryClient::new(e, &storage::get_pool_factory(e));
+ if !pool_factory_client.is_pool(address) {
+ panic_with_error!(e, BackstopError::NotPool);
+ }
}
}
+/// TODO: Duplicated from pool/pool/status.rs. Can this be moved to a common location?
+///
+/// Calculate the threshold for the pool's backstop balance
+///
+/// Returns true if the pool's backstop balance is above the threshold
+/// NOTE: The calculation is the percentage^5 to simplify the calculation of the pools product constant.
+/// Some useful calculation results:
+/// - greater than 1 = 100+%
+/// - 1_0000000 = 100%
+/// - 0_0000100 = ~10%
+/// - 0_0000003 = ~5%
+/// - 0_0000000 = ~0-4%
+pub fn require_pool_above_threshold(pool_backstop_data: &PoolBackstopData) -> bool {
+ // @dev: Calculation for pools product constant of underlying will often overflow i128
+ // so saturating mul is used. This is safe because the threshold is below i128::MAX and the
+ // protocol does not need to differentiate between pools over the threshold product constant.
+ // The calculation is:
+ // - Threshold % = (bal_blnd^4 * bal_usdc) / PC^5 such that PC is 200k
+ let threshold_pc = 320_000_000_000_000_000_000_000_000i128; // 3.2e26 (200k^5)
+ // floor balances to nearest full unit and calculate saturated pool product constant
+ // and scale to SCALAR_7 to get final division result in SCALAR_7 points
+ let bal_blnd = pool_backstop_data.blnd / SCALAR_7;
+ let bal_usdc = pool_backstop_data.usdc / SCALAR_7;
+ let saturating_pool_pc = bal_blnd
+ .saturating_mul(bal_blnd)
+ .saturating_mul(bal_blnd)
+ .saturating_mul(bal_blnd)
+ .saturating_mul(bal_usdc)
+ .saturating_mul(SCALAR_7); // 10^7 * 10^7
+ saturating_pool_pc / threshold_pc >= 1_0000000
+}
+
/// The pool's backstop balances
#[derive(Clone)]
#[contracttype]
@@ -58,20 +99,11 @@ pub struct PoolBalance {
}
impl PoolBalance {
- #[allow(clippy::should_implement_trait)]
- pub fn default() -> PoolBalance {
- PoolBalance {
- shares: 0,
- tokens: 0,
- q4w: 0,
- }
- }
-
/// Convert a token balance to a share balance based on the current pool state
///
/// ### Arguments
/// * `tokens` - the token balance to convert
- pub fn convert_to_shares(&mut self, tokens: i128) -> i128 {
+ pub fn convert_to_shares(&self, tokens: i128) -> i128 {
if self.shares == 0 {
return tokens;
}
@@ -85,7 +117,7 @@ impl PoolBalance {
///
/// ### Arguments
/// * `shares` - the pool share balance to convert
- pub fn convert_to_tokens(&mut self, shares: i128) -> i128 {
+ pub fn convert_to_tokens(&self, shares: i128) -> i128 {
if self.shares == 0 {
return shares;
}
@@ -95,8 +127,15 @@ impl PoolBalance {
.unwrap_optimized()
}
+ /// Determine the amount of effective tokens (not queued for withdrawal) in the pool
+ pub fn non_queued_tokens(&self) -> i128 {
+ self.tokens - self.convert_to_tokens(self.q4w)
+ }
+
/// Deposit tokens and shares into the pool
///
+ /// If this is the first time
+ ///
/// ### Arguments
/// * `tokens` - The amount of tokens to add
/// * `shares` - The amount of shares to add
@@ -152,7 +191,7 @@ mod tests {
let e = Env::default();
let backstop_address = create_backstop(&e);
- let pool = Address::random(&e);
+ let pool = Address::generate(&e);
e.as_contract(&backstop_address, || {
storage::set_pool_balance(
@@ -182,13 +221,28 @@ mod tests {
let e = Env::default();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
+ let pool_address = Address::generate(&e);
let (_, mock_pool_factory) = create_mock_pool_factory(&e, &backstop_address);
mock_pool_factory.set_pool(&pool_address);
e.as_contract(&backstop_address, || {
- require_is_from_pool_factory(&e, &pool_address);
+ require_is_from_pool_factory(&e, &pool_address, 0);
+ assert!(true);
+ });
+ }
+
+ #[test]
+ fn test_require_is_from_pool_factory_skips_if_balance() {
+ let e = Env::default();
+
+ let backstop_address = create_backstop(&e);
+ let pool_address = Address::generate(&e);
+
+ // don't initialize factory to force failure if pool_address is checked
+
+ e.as_contract(&backstop_address, || {
+ require_is_from_pool_factory(&e, &pool_address, 1);
assert!(true);
});
}
@@ -199,23 +253,89 @@ mod tests {
let e = Env::default();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let not_pool_address = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let not_pool_address = Address::generate(&e);
let (_, mock_pool_factory) = create_mock_pool_factory(&e, &backstop_address);
mock_pool_factory.set_pool(&pool_address);
e.as_contract(&backstop_address, || {
- require_is_from_pool_factory(&e, ¬_pool_address);
+ require_is_from_pool_factory(&e, ¬_pool_address, 0);
assert!(false);
});
}
+ /********** require_pool_above_threshold **********/
+
+ #[test]
+ fn test_require_pool_above_threshold_under() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ let pool_backstop_data = PoolBackstopData {
+ blnd: 300_000_0000000,
+ q4w_pct: 0,
+ tokens: 20_000_0000000,
+ usdc: 25_000_0000000,
+ }; // ~91.2% threshold
+
+ let result = require_pool_above_threshold(&pool_backstop_data);
+ assert!(!result);
+ }
+
+ #[test]
+ fn test_require_pool_above_threshold_zero() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ let pool_backstop_data = PoolBackstopData {
+ blnd: 5_000_0000000,
+ q4w_pct: 0,
+ tokens: 500_0000000,
+ usdc: 1_000_0000000,
+ }; // ~3.6% threshold - rounds to zero in calc
+
+ let result = require_pool_above_threshold(&pool_backstop_data);
+ assert!(!result);
+ }
+
+ #[test]
+ fn test_require_pool_above_threshold_over() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ let pool_backstop_data = PoolBackstopData {
+ blnd: 364_643_0000000,
+ q4w_pct: 0,
+ tokens: 15_000_0000000,
+ usdc: 18_100_0000000,
+ }; // 100% threshold
+
+ let result = require_pool_above_threshold(&pool_backstop_data);
+ assert!(result);
+ }
+
+ #[test]
+ fn test_require_pool_above_threshold_saturates() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ let pool_backstop_data = PoolBackstopData {
+ blnd: 50_000_000_0000000,
+ q4w_pct: 0,
+ tokens: 999_999_0000000,
+ usdc: 10_000_000_0000000,
+ }; // 181x threshold
+
+ let result = require_pool_above_threshold(&pool_backstop_data);
+ assert!(result);
+ }
+
/********** Logic **********/
#[test]
fn test_convert_to_shares_no_shares() {
- let mut pool_balance = PoolBalance {
+ let pool_balance = PoolBalance {
shares: 0,
tokens: 0,
q4w: 0,
@@ -228,7 +348,7 @@ mod tests {
#[test]
fn test_convert_to_shares() {
- let mut pool_balance = PoolBalance {
+ let pool_balance = PoolBalance {
shares: 80321,
tokens: 103302,
q4w: 0,
@@ -241,7 +361,7 @@ mod tests {
#[test]
fn test_convert_to_tokens_no_shares() {
- let mut pool_balance = PoolBalance {
+ let pool_balance = PoolBalance {
shares: 0,
tokens: 0,
q4w: 0,
@@ -254,7 +374,7 @@ mod tests {
#[test]
fn test_convert_to_tokens() {
- let mut pool_balance = PoolBalance {
+ let pool_balance = PoolBalance {
shares: 80321,
tokens: 103302,
q4w: 0,
diff --git a/backstop/src/backstop/user.rs b/backstop/src/backstop/user.rs
index 28b6488b..1773929b 100644
--- a/backstop/src/backstop/user.rs
+++ b/backstop/src/backstop/user.rs
@@ -155,9 +155,9 @@ mod tests {
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_queue = 500;
@@ -196,9 +196,9 @@ mod tests {
timestamp: 11000000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_queue = 500;
@@ -233,9 +233,9 @@ mod tests {
timestamp: 11000000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_queue = 801;
@@ -258,9 +258,9 @@ mod tests {
timestamp: 11000000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_wd = 1;
@@ -289,9 +289,9 @@ mod tests {
timestamp: 12592000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_wd = 200;
@@ -323,9 +323,9 @@ mod tests {
timestamp: 12592000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_wd = 150;
@@ -372,9 +372,9 @@ mod tests {
timestamp: 22592000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_wd = 300;
@@ -426,9 +426,9 @@ mod tests {
timestamp: 11192000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_wd = 300;
@@ -466,9 +466,9 @@ mod tests {
timestamp: 11192000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_dequeue = 300;
// verify exp is respected when specified
@@ -505,9 +505,9 @@ mod tests {
timestamp: 11192000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let to_dequeue = 376;
diff --git a/backstop/src/backstop/withdrawal.rs b/backstop/src/backstop/withdrawal.rs
index ba936c42..fd68dcb9 100644
--- a/backstop/src/backstop/withdrawal.rs
+++ b/backstop/src/backstop/withdrawal.rs
@@ -76,7 +76,9 @@ mod tests {
use crate::{
backstop::{execute_deposit, execute_donate},
- testutils::{assert_eq_vec_q4w, create_backstop, create_backstop_token},
+ testutils::{
+ assert_eq_vec_q4w, create_backstop, create_backstop_token, create_mock_pool_factory,
+ },
};
use super::*;
@@ -87,13 +89,16 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
// setup pool with deposits
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_address, 100_0000000);
@@ -105,9 +110,9 @@ mod tests {
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
@@ -144,13 +149,16 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
// setup pool with deposits
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_address, 100_0000000);
@@ -162,9 +170,9 @@ mod tests {
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
@@ -178,13 +186,16 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
// queue shares for withdraw
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_address, 75_0000000);
@@ -196,9 +207,9 @@ mod tests {
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
execute_queue_withdrawal(&e, &samwise, &pool_address, 40_0000000);
@@ -210,9 +221,9 @@ mod tests {
timestamp: 20000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
@@ -242,13 +253,16 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &100_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
// queue shares for withdraw
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_address, 75_0000000);
@@ -260,9 +274,9 @@ mod tests {
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
execute_queue_withdrawal(&e, &samwise, &pool_address, 40_0000000);
@@ -274,9 +288,9 @@ mod tests {
timestamp: 20000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
@@ -290,22 +304,25 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &150_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
e.ledger().set(LedgerInfo {
protocol_version: 20,
sequence_number: 200,
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
// setup pool with queue for withdrawal and allow the backstop to incur a profit
@@ -321,9 +338,9 @@ mod tests {
timestamp: 10000 + 30 * 24 * 60 * 60 + 1,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
@@ -353,22 +370,25 @@ mod tests {
e.mock_all_auths_allowing_non_root_auth();
let backstop_address = create_backstop(&e);
- let pool_address = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_address = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
let (_, backstop_token_client) = create_backstop_token(&e, &backstop_address, &bombadil);
backstop_token_client.mint(&samwise, &150_0000000);
+ let (_, mock_pool_factory_client) = create_mock_pool_factory(&e, &backstop_address);
+ mock_pool_factory_client.set_pool(&pool_address);
+
e.ledger().set(LedgerInfo {
protocol_version: 20,
sequence_number: 200,
timestamp: 10000,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
// setup pool with queue for withdrawal and allow the backstop to incur a profit
@@ -384,9 +404,9 @@ mod tests {
timestamp: 10000 + 30 * 24 * 60 * 60 + 1,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.as_contract(&backstop_address, || {
diff --git a/backstop/src/contract.rs b/backstop/src/contract.rs
index 0e0b4c1d..39434b90 100644
--- a/backstop/src/contract.rs
+++ b/backstop/src/contract.rs
@@ -1,5 +1,6 @@
use crate::{
backstop::{self, load_pool_backstop_data, PoolBackstopData, UserBalance, Q4W},
+ dependencies::EmitterClient,
emissions,
errors::BackstopError,
storage,
@@ -18,8 +19,11 @@ pub struct BackstopContract;
pub trait Backstop {
/// Initialize the backstop
///
+ /// This function requires that the Emitter has already been initialized
+ ///
/// ### Arguments
/// * `backstop_token` - The backstop token ID - an LP token with the pair BLND:USDC
+ /// * `emitter` - The Emitter contract ID
/// * `blnd_token` - The BLND token ID
/// * `usdc_token` - The USDC token ID
/// * `pool_factory` - The pool factory ID
@@ -30,6 +34,7 @@ pub trait Backstop {
fn initialize(
e: Env,
backstop_token: Address,
+ emitter: Address,
blnd_token: Address,
usdc_token: Address,
pool_factory: Address,
@@ -96,8 +101,8 @@ pub trait Backstop {
/********** Emissions **********/
- /// Update the backstop for the next emissions cycle from the Emitter
- fn update_emission_cycle(e: Env);
+ /// Consume emissions from the Emitter and distribute them to backstops and pools in the reward zone
+ fn gulp_emissions(e: Env);
/// Add a pool to the reward zone, and if the reward zone is full, a pool to remove
///
@@ -109,9 +114,8 @@ pub trait Backstop {
/// If the pool to remove has more tokens, or if distribution occurred in the last 48 hours
fn add_reward(e: Env, to_add: Address, to_remove: Address);
- /// Fetch the EPS (emissions per second) and expiration for the current distribution window of a pool
- /// in a tuple where (EPS, expiration)
- fn pool_eps(e: Env, pool_address: Address) -> (i128, u64);
+ /// Consume the emissions for a pool and approve
+ fn gulp_pool_emissions(e: Env, pool_address: Address) -> i128;
/// Claim backstop deposit emissions from a list of pools for `from`
///
@@ -126,8 +130,8 @@ pub trait Backstop {
/// If an invalid pool address is included
fn claim(e: Env, from: Address, pool_addresses: Vec
, to: Address) -> i128;
- /// Fetch the drop list
- fn drop_list(e: Env) -> Map;
+ /// Drop initial BLND to a list of addresses through the emitter
+ fn drop(e: Env);
/********** Fund Management *********/
@@ -196,12 +200,13 @@ impl Backstop for BackstopContract {
fn initialize(
e: Env,
backstop_token: Address,
+ emitter: Address,
usdc_token: Address,
blnd_token: Address,
pool_factory: Address,
drop_list: Map,
) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
if storage::has_backstop_token(&e) {
panic_with_error!(e, BackstopError::AlreadyInitialized);
}
@@ -211,12 +216,20 @@ impl Backstop for BackstopContract {
storage::set_usdc_token(&e, &usdc_token);
storage::set_pool_factory(&e, &pool_factory);
storage::set_drop_list(&e, &drop_list);
+ storage::set_emitter(&e, &emitter);
+
+ // fetch last distribution time from emitter
+ // NOTE: For a replacement backstop, this must be fetched after the swap is completed, but this is
+ // a shortcut for the first backstop.
+ let last_distribution_time =
+ EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address());
+ storage::set_last_distribution_time(&e, &last_distribution_time);
}
/********** Core **********/
fn deposit(e: Env, from: Address, pool_address: Address, amount: i128) -> i128 {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
let to_mint = backstop::execute_deposit(&e, &from, &pool_address, amount);
@@ -229,7 +242,7 @@ impl Backstop for BackstopContract {
}
fn queue_withdrawal(e: Env, from: Address, pool_address: Address, amount: i128) -> Q4W {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
let to_queue = backstop::execute_queue_withdrawal(&e, &from, &pool_address, amount);
@@ -242,7 +255,7 @@ impl Backstop for BackstopContract {
}
fn dequeue_withdrawal(e: Env, from: Address, pool_address: Address, amount: i128) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
backstop::execute_dequeue_withdrawal(&e, &from, &pool_address, amount);
@@ -254,7 +267,7 @@ impl Backstop for BackstopContract {
}
fn withdraw(e: Env, from: Address, pool_address: Address, amount: i128) -> i128 {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
let to_withdraw = backstop::execute_withdraw(&e, &from, &pool_address, amount);
@@ -280,28 +293,30 @@ impl Backstop for BackstopContract {
/********** Emissions **********/
- fn update_emission_cycle(e: Env) {
- storage::bump_instance(&e);
- emissions::update_emission_cycle(&e);
+ fn gulp_emissions(e: Env) {
+ storage::extend_instance(&e);
+ let new_tokens_emitted = emissions::gulp_emissions(&e);
+
+ e.events()
+ .publish((Symbol::new(&e, "gulp_emissions"),), new_tokens_emitted);
}
fn add_reward(e: Env, to_add: Address, to_remove: Address) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
emissions::add_to_reward_zone(&e, to_add.clone(), to_remove.clone());
e.events()
.publish((Symbol::new(&e, "rw_zone"),), (to_add, to_remove));
}
- fn pool_eps(e: Env, pool_address: Address) -> (i128, u64) {
- (
- storage::get_pool_eps(&e, &pool_address),
- storage::get_next_emission_cycle(&e),
- )
+ fn gulp_pool_emissions(e: Env, pool_address: Address) -> i128 {
+ storage::extend_instance(&e);
+ pool_address.require_auth();
+ emissions::gulp_pool_emissions(&e, &pool_address)
}
fn claim(e: Env, from: Address, pool_addresses: Vec, to: Address) -> i128 {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
let amount = emissions::execute_claim(&e, &from, &pool_addresses, &to);
@@ -310,14 +325,14 @@ impl Backstop for BackstopContract {
amount
}
- fn drop_list(e: Env) -> Map {
- storage::get_drop_list(&e)
+ fn drop(e: Env) {
+ EmitterClient::new(&e, &storage::get_emitter(&e)).drop(&storage::get_drop_list(&e))
}
/********** Fund Management *********/
fn draw(e: Env, pool_address: Address, amount: i128, to: Address) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
pool_address.require_auth();
backstop::execute_draw(&e, &pool_address, amount, &to);
@@ -327,7 +342,7 @@ impl Backstop for BackstopContract {
}
fn donate(e: Env, from: Address, pool_address: Address, amount: i128) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
backstop::execute_donate(&e, &from, &pool_address, amount);
@@ -336,7 +351,7 @@ impl Backstop for BackstopContract {
}
fn donate_usdc(e: Env, from: Address, pool_address: Address, amount: i128) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
from.require_auth();
backstop::execute_donate_usdc(&e, &from, &pool_address, amount);
@@ -345,21 +360,15 @@ impl Backstop for BackstopContract {
}
fn gulp_usdc(e: Env, pool_address: Address) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
backstop::execute_gulp_usdc(&e, &pool_address);
- e.events().publish(
- (
- Symbol::new(&e, "gulp_usdc"),
- pool_address,
- e.call_stack().last_unchecked().0,
- ),
- (),
- );
+ e.events()
+ .publish((Symbol::new(&e, "gulp_usdc"), pool_address), ());
}
fn update_tkn_val(e: Env) -> (i128, i128) {
- storage::bump_instance(&e);
+ storage::extend_instance(&e);
let backstop_token = storage::get_backstop_token(&e);
let blnd_token = storage::get_blnd_token(&e);
diff --git a/emitter/src/dependencies/backstop.rs b/backstop/src/dependencies/emitter.rs
similarity index 84%
rename from emitter/src/dependencies/backstop.rs
rename to backstop/src/dependencies/emitter.rs
index 00624246..2ee529dd 100644
--- a/emitter/src/dependencies/backstop.rs
+++ b/backstop/src/dependencies/emitter.rs
@@ -1,3 +1,3 @@
use soroban_sdk::contractimport;
-contractimport!(file = "../target/wasm32-unknown-unknown/release/backstop.wasm");
+contractimport!(file = "../target/wasm32-unknown-unknown/release/emitter.wasm");
diff --git a/backstop/src/dependencies/mod.rs b/backstop/src/dependencies/mod.rs
index 53892d25..89463a25 100644
--- a/backstop/src/dependencies/mod.rs
+++ b/backstop/src/dependencies/mod.rs
@@ -5,3 +5,6 @@ mod comet;
pub use comet::Client as CometClient;
#[cfg(any(test, feature = "testutils"))]
pub use comet::WASM as COMET_WASM;
+
+mod emitter;
+pub use emitter::Client as EmitterClient;
diff --git a/backstop/src/emissions/claim.rs b/backstop/src/emissions/claim.rs
index f7e5b5e1..e9019a7b 100644
--- a/backstop/src/emissions/claim.rs
+++ b/backstop/src/emissions/claim.rs
@@ -1,5 +1,5 @@
use crate::{dependencies::CometClient, errors::BackstopError, storage};
-use fixed_point_math::FixedPoint;
+use soroban_fixed_point_math::FixedPoint;
use soroban_sdk::{
auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation},
panic_with_error, vec, Address, Env, IntoVal, Map, Symbol, Val, Vec,
@@ -7,8 +7,6 @@ use soroban_sdk::{
use super::update_emissions;
-// TODO: Deposit emissions back into the backstop automatically after 80/20 BLND deposit function added
-
/// Perform a claim for backstop deposit emissions by a user from the backstop module
pub fn execute_claim(e: &Env, from: &Address, pool_addresses: &Vec, to: &Address) -> i128 {
if pool_addresses.is_empty() {
@@ -106,18 +104,18 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
e.budget().reset_unlimited();
let backstop_address = create_backstop(&e);
- let pool_1_id = Address::random(&e);
- let pool_2_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_1_id = Address::generate(&e);
+ let pool_2_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (blnd_address, blnd_token_client) = create_blnd_token(&e, &backstop_address, &bombadil);
let (usdc_address, _) = create_usdc_token(&e, &backstop_address, &bombadil);
@@ -267,17 +265,17 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_address = create_backstop(&e);
- let pool_1_id = Address::random(&e);
- let pool_2_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_1_id = Address::generate(&e);
+ let pool_2_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (blnd_address, blnd_token_client) = create_blnd_token(&e, &backstop_address, &bombadil);
let (usdc_address, _) = create_usdc_token(&e, &backstop_address, &bombadil);
@@ -418,9 +416,9 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_lp_balance = backstop_lp_balance + 6_5244800;
let pre_frodo_balance_1 = storage::get_user_balance(&e, &pool_1_id, &frodo).shares;
@@ -490,17 +488,17 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_address = create_backstop(&e);
- let pool_1_id = Address::random(&e);
- let pool_2_id = Address::random(&e);
- let bombadil = Address::random(&e);
- let samwise = Address::random(&e);
- let frodo = Address::random(&e);
+ let pool_1_id = Address::generate(&e);
+ let pool_2_id = Address::generate(&e);
+ let bombadil = Address::generate(&e);
+ let samwise = Address::generate(&e);
+ let frodo = Address::generate(&e);
let (_, blnd_token_client) = create_blnd_token(&e, &backstop_address, &bombadil);
blnd_token_client.mint(&backstop_address, &100_0000000);
diff --git a/backstop/src/emissions/distributor.rs b/backstop/src/emissions/distributor.rs
index a75674c5..1af1fb6b 100644
--- a/backstop/src/emissions/distributor.rs
+++ b/backstop/src/emissions/distributor.rs
@@ -1,11 +1,14 @@
+//! Methods for distributing backstop emissions to depositors
+
use cast::i128;
-use fixed_point_math::FixedPoint;
+use soroban_fixed_point_math::FixedPoint;
use soroban_sdk::{unwrap::UnwrapOptimized, Address, Env};
use crate::{
backstop::{PoolBalance, UserBalance},
constants::SCALAR_7,
storage::{self, BackstopEmissionsData, UserEmissionData},
+ BackstopEmissionConfig,
};
/// Update the backstop emissions index for the user and pool
@@ -33,10 +36,23 @@ pub fn update_emission_data(
pool_id: &Address,
pool_balance: &PoolBalance,
) -> Option {
- let emis_config = match storage::get_backstop_emis_config(e, pool_id) {
- Some(res) => res,
+ match storage::get_backstop_emis_config(e, pool_id) {
+ Some(config) => Some(update_emission_data_with_config(
+ e,
+ pool_id,
+ pool_balance,
+ &config,
+ )),
None => return None, // no emission exist, no update is required
- };
+ }
+}
+
+pub fn update_emission_data_with_config(
+ e: &Env,
+ pool_id: &Address,
+ pool_balance: &PoolBalance,
+ emis_config: &BackstopEmissionConfig,
+) -> BackstopEmissionsData {
let emis_data = storage::get_backstop_emis_data(e, pool_id).unwrap_optimized(); // exists if config is written to
if emis_data.last_time >= emis_config.expiration
@@ -45,7 +61,7 @@ pub fn update_emission_data(
|| pool_balance.shares == 0
{
// emis_data already updated or expired
- return Some(emis_data);
+ return emis_data;
}
let max_timestamp = if e.ledger().timestamp() > emis_config.expiration {
@@ -62,7 +78,7 @@ pub fn update_emission_data(
last_time: e.ledger().timestamp(),
};
storage::set_backstop_emis_data(e, pool_id, &new_data);
- Some(new_data)
+ new_data
}
fn update_user_emissions(
@@ -139,14 +155,14 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
let backstop_emissions_config = BackstopEmissionConfig {
expiration: BACKSTOP_EPOCH + 7 * 24 * 60 * 60,
@@ -161,7 +177,7 @@ mod tests {
accrued: 3,
};
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
storage::set_backstop_emis_config(&e, &pool_1, &backstop_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &backstop_emissions_data);
storage::set_user_emis_data(&e, &pool_1, &samwise, &user_emissions_data);
@@ -200,17 +216,17 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
let pool_balance = PoolBalance {
shares: 150_0000000,
@@ -243,14 +259,14 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
let backstop_emissions_config = BackstopEmissionConfig {
expiration: BACKSTOP_EPOCH + 7 * 24 * 60 * 60,
@@ -265,7 +281,7 @@ mod tests {
accrued: 3,
};
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
storage::set_backstop_emis_config(&e, &pool_1, &backstop_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &backstop_emissions_data);
storage::set_user_emis_data(&e, &pool_1, &samwise, &user_emissions_data);
@@ -304,14 +320,14 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
let backstop_emissions_config = BackstopEmissionConfig {
expiration: BACKSTOP_EPOCH + 7 * 24 * 60 * 60,
@@ -322,7 +338,7 @@ mod tests {
last_time: BACKSTOP_EPOCH,
};
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
storage::set_backstop_emis_config(&e, &pool_1, &backstop_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &backstop_emissions_data);
@@ -360,14 +376,14 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
let backstop_emissions_config = BackstopEmissionConfig {
expiration: BACKSTOP_EPOCH + 7 * 24 * 60 * 60,
@@ -378,7 +394,7 @@ mod tests {
last_time: BACKSTOP_EPOCH,
};
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
storage::set_backstop_emis_config(&e, &pool_1, &backstop_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &backstop_emissions_data);
@@ -415,14 +431,14 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let samwise = Address::random(&e);
+ let pool_1 = Address::generate(&e);
+ let samwise = Address::generate(&e);
let backstop_emissions_config = BackstopEmissionConfig {
expiration: BACKSTOP_EPOCH + 7 * 24 * 60 * 60,
@@ -437,7 +453,7 @@ mod tests {
accrued: 3,
};
e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 7 * 24 * 60 * 60));
+ storage::set_last_distribution_time(&e, &BACKSTOP_EPOCH);
storage::set_backstop_emis_config(&e, &pool_1, &backstop_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &backstop_emissions_data);
storage::set_user_emis_data(&e, &pool_1, &samwise, &user_emissions_data);
diff --git a/backstop/src/emissions/manager.rs b/backstop/src/emissions/manager.rs
index 6fa74477..58a53a3e 100644
--- a/backstop/src/emissions/manager.rs
+++ b/backstop/src/emissions/manager.rs
@@ -1,15 +1,18 @@
use cast::{i128, u64};
-use fixed_point_math::FixedPoint;
use sep_41_token::TokenClient;
+use soroban_fixed_point_math::FixedPoint;
use soroban_sdk::{panic_with_error, unwrap::UnwrapOptimized, vec, Address, Env, Vec};
use crate::{
+ backstop::{load_pool_backstop_data, require_pool_above_threshold},
constants::{BACKSTOP_EPOCH, SCALAR_7},
+ dependencies::EmitterClient,
errors::BackstopError,
storage::{self, BackstopEmissionConfig, BackstopEmissionsData},
+ PoolBalance,
};
-use super::update_emission_data;
+use super::distributor::update_emission_data_with_config;
/// Add a pool to the reward zone. If the reward zone is full, attempt to swap it with the pool to remove.
pub fn add_to_reward_zone(e: &Env, to_add: Address, to_remove: Address) {
@@ -21,33 +24,33 @@ pub fn add_to_reward_zone(e: &Env, to_add: Address, to_remove: Address) {
panic_with_error!(e, BackstopError::BadRequest);
}
+ // enusre to_add has met the minimum backstop deposit threshold
+ // NOTE: "to_add" can only carry a pool balance if it is a deployed pool from the factory
+ let pool_data = load_pool_backstop_data(e, &to_add);
+ if !require_pool_above_threshold(&pool_data) {
+ panic_with_error!(e, BackstopError::InvalidRewardZoneEntry);
+ }
+
if max_rz_len > i128(reward_zone.len()) {
- // there is room in the reward zone. Add whatever
- // TODO: Once there is a defined limit of "backstop minimum", ensure it is reached!
+ // there is room in the reward zone. Add "to_add".
reward_zone.push_front(to_add.clone());
} else {
- // don't allow rz modifications within 48 hours of the start of an emission cycle
- // if pools don't adopt their emissions within this time frame and get swapped, the tokens will be lost
- let next_distribution = storage::get_next_emission_cycle(e);
- if next_distribution != 0 && e.ledger().timestamp() < next_distribution - 5 * 24 * 60 * 60 {
- panic_with_error!(e, BackstopError::BadRequest);
- }
-
- // attempt to swap the "to_remove"
- // TODO: Once there is a defined limit of "backstop minimum", ensure it is reached!
- if storage::get_pool_balance(e, &to_add).tokens
- <= storage::get_pool_balance(e, &to_remove).tokens
- {
- panic_with_error!(e, BackstopError::InvalidRewardZoneEntry);
- }
-
// swap to_add for to_remove
let to_remove_index = reward_zone.first_index_of(to_remove.clone());
match to_remove_index {
Some(idx) => {
+ // verify distribute was run recently to prevent "to_remove" from losing excess emissions
+ // @dev: resource constraints prevent us from distributing on reward zone changes
+ let last_distribution = storage::get_last_distribution_time(e);
+ if last_distribution < e.ledger().timestamp() - 24 * 60 * 60 {
+ panic_with_error!(e, BackstopError::BadRequest);
+ }
+
+ // Verify "to_add" has a higher backstop deposit that "to_remove"
+ if pool_data.tokens <= storage::get_pool_balance(e, &to_remove).tokens {
+ panic_with_error!(e, BackstopError::InvalidRewardZoneEntry);
+ }
reward_zone.set(idx, to_add.clone());
- storage::set_pool_eps(e, &to_remove, &0);
- // emissions data is not updated. Emissions will be set on the next emission cycle
}
None => panic_with_error!(e, BackstopError::InvalidRewardZoneEntry),
}
@@ -56,80 +59,112 @@ pub fn add_to_reward_zone(e: &Env, to_add: Address, to_remove: Address) {
storage::set_reward_zone(e, &reward_zone);
}
-/// Update the backstop for the next emission cycle from the Emitter
+/// Assign emissions from the Emitter to backstops and pools in the reward zone
#[allow(clippy::zero_prefixed_literal)]
-pub fn update_emission_cycle(e: &Env) {
- if e.ledger().timestamp() < storage::get_next_emission_cycle(e) {
+pub fn gulp_emissions(e: &Env) -> i128 {
+ let emitter = storage::get_emitter(e);
+ let emitter_last_distribution =
+ EmitterClient::new(&e, &emitter).get_last_distro(&e.current_contract_address());
+ let last_distribution = storage::get_last_distribution_time(e);
+
+ // ensure enough time has passed between the last emitter distribution and gulp_emissions
+ // to prevent excess rounding issues
+ if emitter_last_distribution <= (last_distribution + 60 * 60) {
panic_with_error!(e, BackstopError::BadRequest);
}
- let next_distribution = e.ledger().timestamp() + 7 * 24 * 60 * 60;
- storage::set_next_emission_cycle(e, &next_distribution);
+ storage::set_last_distribution_time(e, &emitter_last_distribution);
+ let new_emissions = i128(emitter_last_distribution - last_distribution) * SCALAR_7; // emitter releases 1 token per second
+ let total_backstop_emissions = new_emissions
+ .fixed_mul_floor(0_7000000, SCALAR_7)
+ .unwrap_optimized();
+ let total_pool_emissions = new_emissions
+ .fixed_mul_floor(0_3000000, SCALAR_7)
+ .unwrap_optimized();
let reward_zone = storage::get_reward_zone(e);
let rz_len = reward_zone.len();
- let mut rz_tokens: Vec = vec![e];
+ let mut rz_balance: Vec = vec![e];
// TODO: Potential to assume optimization of backstop token balances ~= RZ tokens
// However, linear iteration over the RZ will still occur
// fetch total tokens of BLND in the reward zone
- let mut total_tokens: i128 = 0;
+ let mut total_non_queued_tokens: i128 = 0;
for rz_pool_index in 0..rz_len {
let rz_pool = reward_zone.get(rz_pool_index).unwrap_optimized();
- let mut pool_balance = storage::get_pool_balance(e, &rz_pool);
- let net_deposits =
- pool_balance.tokens.clone() - pool_balance.convert_to_tokens(pool_balance.q4w.clone());
- rz_tokens.push_back(net_deposits);
- total_tokens += net_deposits;
+ let pool_balance = storage::get_pool_balance(e, &rz_pool);
+ total_non_queued_tokens += pool_balance.non_queued_tokens();
+ rz_balance.push_back(pool_balance);
}
- let blnd_token_client = TokenClient::new(e, &storage::get_blnd_token(e));
// store pools EPS and distribute emissions to backstop depositors
for rz_pool_index in 0..rz_len {
let rz_pool = reward_zone.get(rz_pool_index).unwrap_optimized();
- let cur_pool_tokens = rz_tokens.pop_front_unchecked();
- let share = cur_pool_tokens
- .fixed_div_floor(total_tokens, SCALAR_7)
+ let cur_pool_balance = rz_balance.pop_front_unchecked();
+ let cur_pool_non_queued_tokens = cur_pool_balance.non_queued_tokens();
+ let share = cur_pool_non_queued_tokens
+ .fixed_div_floor(total_non_queued_tokens, SCALAR_7)
.unwrap_optimized();
// store pool EPS and distribute pool's emissions via allowances to pool
- let pool_eps = share
- .fixed_mul_floor(0_3000000, SCALAR_7)
+ let new_pool_emissions = share
+ .fixed_mul_floor(total_pool_emissions, SCALAR_7)
.unwrap_optimized();
- let new_pool_emissions = pool_eps * 7 * 24 * 60 * 60;
- let current_allowance =
- blnd_token_client.allowance(&e.current_contract_address(), &rz_pool);
- blnd_token_client.approve(
- &e.current_contract_address(),
- &rz_pool,
- &(current_allowance + new_pool_emissions),
- &(e.ledger().sequence() + 17_280 * 30), // ~30 days: TODO: check phase 1 limits
- );
- storage::set_pool_eps(e, &rz_pool, &pool_eps);
+ let current_emissions = storage::get_pool_emissions(e, &rz_pool);
+ storage::set_pool_emissions(e, &rz_pool, current_emissions + new_pool_emissions);
// distribute backstop depositor emissions
- let pool_backstop_eps = share
- .fixed_mul_floor(0_7000000, SCALAR_7)
+ let new_pool_backstop_tokens = share
+ .fixed_mul_floor(total_backstop_emissions, SCALAR_7)
.unwrap_optimized();
- set_backstop_emission_config(
- e,
- &rz_pool,
- u64(pool_backstop_eps).unwrap_optimized(),
- next_distribution,
- );
+ set_backstop_emission_config(e, &rz_pool, &cur_pool_balance, new_pool_backstop_tokens);
+ }
+ new_emissions
+}
+
+/// Consume pool emissions approve them to be transferred by the pool
+pub fn gulp_pool_emissions(e: &Env, pool_id: &Address) -> i128 {
+ let pool_emissions = storage::get_pool_emissions(e, pool_id);
+ if pool_emissions == 0 {
+ panic_with_error!(e, BackstopError::BadRequest);
}
+
+ let blnd_token_client = TokenClient::new(e, &storage::get_blnd_token(e));
+ let current_allowance = blnd_token_client.allowance(&e.current_contract_address(), pool_id);
+ let new_tokens = current_allowance + pool_emissions;
+ let new_seq = e.ledger().sequence() + 17_280 * 30; // ~30 days: TODO: check phase 1 limits
+ blnd_token_client.approve(
+ &e.current_contract_address(),
+ pool_id,
+ &new_tokens,
+ &new_seq, // ~30 days: TODO: check phase 1 limits
+ );
+ storage::set_pool_emissions(e, pool_id, 0);
+ pool_emissions
}
/// Set a new EPS for the backstop
-pub fn set_backstop_emission_config(e: &Env, pool_id: &Address, eps: u64, expiration: u64) {
- if storage::has_backstop_emis_config(e, pool_id) {
+pub fn set_backstop_emission_config(
+ e: &Env,
+ pool_id: &Address,
+ pool_balance: &PoolBalance,
+ new_tokens: i128,
+) {
+ let mut tokens_left_to_emit = new_tokens;
+ if let Some(emis_config) = storage::get_backstop_emis_config(e, pool_id) {
// a previous config exists - update with old config before setting new EPS
- let pool_balance = storage::get_pool_balance(e, pool_id);
- let mut emission_data = update_emission_data(e, pool_id, &pool_balance).unwrap_optimized();
+ let mut emission_data =
+ update_emission_data_with_config(e, pool_id, &pool_balance, &emis_config);
if emission_data.last_time != e.ledger().timestamp() {
// force the emission data to be updated to the current timestamp
emission_data.last_time = e.ledger().timestamp();
storage::set_backstop_emis_data(e, pool_id, &emission_data);
}
+ // determine the amount of tokens not emitted from the last config
+ if emis_config.expiration > e.ledger().timestamp() {
+ let time_since_last_emission = emis_config.expiration - e.ledger().timestamp();
+ let tokens_since_last_emission = i128(emis_config.eps * time_since_last_emission);
+ tokens_left_to_emit += tokens_since_last_emission;
+ }
} else {
// first time the pool's backstop is receiving emissions - ensure data is written
storage::set_backstop_emis_data(
@@ -141,6 +176,8 @@ pub fn set_backstop_emission_config(e: &Env, pool_id: &Address, eps: u64, expira
},
);
}
+ let expiration = e.ledger().timestamp() + 7 * 24 * 60 * 60;
+ let eps = u64(tokens_left_to_emit / (7 * 24 * 60 * 60)).unwrap_optimized();
let backstop_emis_config = BackstopEmissionConfig { expiration, eps };
storage::set_backstop_emis_config(e, pool_id, &backstop_emis_config);
}
@@ -151,19 +188,19 @@ mod tests {
use super::*;
use soroban_sdk::{
testutils::{Address as _, Ledger, LedgerInfo},
- vec, BytesN, Vec,
+ vec, Vec,
};
use crate::{
backstop::PoolBalance,
storage::BackstopEmissionConfig,
- testutils::{self, create_backstop},
+ testutils::{create_backstop, create_blnd_token, create_emitter},
};
- /********** update_emission_cycle **********/
+ /********** gulp_emissions **********/
#[test]
- fn test_update_emission_cycle_happy_path() {
+ fn test_gulp_emissions() {
let e = Env::default();
e.budget().reset_unlimited();
@@ -173,38 +210,59 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
- let bombadil = Address::random(&e);
let backstop = create_backstop(&e);
- let (_, blnd_token_client) = testutils::create_blnd_token(&e, &backstop, &bombadil);
- let pool_1 = Address::random(&e);
- let pool_2 = Address::random(&e);
- let pool_3 = Address::random(&e);
+ let emitter_distro_time = BACKSTOP_EPOCH - 10;
+ create_emitter(
+ &e,
+ &backstop,
+ &Address::generate(&e),
+ &Address::generate(&e),
+ emitter_distro_time,
+ );
+ let pool_1 = Address::generate(&e);
+ let pool_2 = Address::generate(&e);
+ let pool_3 = Address::generate(&e);
let reward_zone: Vec = vec![&e, pool_1.clone(), pool_2.clone(), pool_3.clone()];
+ // setup pool 1 to have ongoing emissions
let pool_1_emissions_config = BackstopEmissionConfig {
- expiration: BACKSTOP_EPOCH,
+ expiration: BACKSTOP_EPOCH + 1000,
eps: 0_1000000,
};
let pool_1_emissions_data = BackstopEmissionsData {
index: 887766,
last_time: BACKSTOP_EPOCH - 12345,
};
+
+ // setup pool 2 to have expired emissions
+ let pool_2_emissions_config = BackstopEmissionConfig {
+ expiration: BACKSTOP_EPOCH - 12345,
+ eps: 0_0500000,
+ };
+ let pool_2_emissions_data = BackstopEmissionsData {
+ index: 453234,
+ last_time: BACKSTOP_EPOCH - 12345,
+ };
+ // setup pool 3 to have no emissions
e.as_contract(&backstop, || {
- storage::set_next_emission_cycle(&e, &BACKSTOP_EPOCH);
+ storage::set_last_distribution_time(&e, &(emitter_distro_time - 7 * 24 * 60 * 60));
storage::set_reward_zone(&e, &reward_zone);
storage::set_backstop_emis_config(&e, &pool_1, &pool_1_emissions_config);
storage::set_backstop_emis_data(&e, &pool_1, &pool_1_emissions_data);
+ storage::set_pool_emissions(&e, &pool_1, 100_123_0000000);
+ storage::set_backstop_emis_config(&e, &pool_2, &pool_2_emissions_config);
+ storage::set_backstop_emis_data(&e, &pool_2, &pool_2_emissions_data);
storage::set_pool_balance(
&e,
&pool_1,
&PoolBalance {
tokens: 300_000_0000000,
- shares: 300_000_0000000,
+ shares: 200_000_0000000,
q4w: 0,
},
);
@@ -213,7 +271,7 @@ mod tests {
&pool_2,
&PoolBalance {
tokens: 200_000_0000000,
- shares: 200_000_0000000,
+ shares: 150_000_0000000,
q4w: 0,
},
);
@@ -222,18 +280,15 @@ mod tests {
&pool_3,
&PoolBalance {
tokens: 500_000_0000000,
- shares: 500_000_0000000,
+ shares: 600_000_0000000,
q4w: 0,
},
);
- blnd_token_client.approve(&backstop, &pool_1, &100_123_0000000, &1000000);
+ // blnd_token_client.approve(&backstop, &pool_1, &100_123_0000000, &1000000);
- update_emission_cycle(&e);
+ gulp_emissions(&e);
- assert_eq!(
- storage::get_next_emission_cycle(&e),
- BACKSTOP_EPOCH + 7 * 24 * 60 * 60
- );
+ assert_eq!(storage::get_last_distribution_time(&e), emitter_distro_time);
assert_eq!(
storage::get_pool_balance(&e, &pool_1).tokens,
300_000_0000000
@@ -246,32 +301,22 @@ mod tests {
storage::get_pool_balance(&e, &pool_3).tokens,
500_000_0000000
);
- assert_eq!(storage::get_pool_eps(&e, &pool_1), 0_0900000);
- assert_eq!(storage::get_pool_eps(&e, &pool_2), 0_0600000);
- assert_eq!(storage::get_pool_eps(&e, &pool_3), 0_1500000);
- assert_eq!(
- blnd_token_client.allowance(&backstop, &pool_1),
- 154_555_0000000
- );
- assert_eq!(
- blnd_token_client.allowance(&backstop, &pool_2),
- 36_288_0000000
- );
- assert_eq!(
- blnd_token_client.allowance(&backstop, &pool_3),
- 90_720_0000000
- );
+ assert_eq!(storage::get_pool_emissions(&e, &pool_1), 154_555_0000000);
+ assert_eq!(storage::get_pool_emissions(&e, &pool_2), 36_288_0000000);
+ assert_eq!(storage::get_pool_emissions(&e, &pool_3), 90_720_0000000);
+
+ // validate backstop emissions
let new_pool_1_config =
storage::get_backstop_emis_config(&e, &pool_1).unwrap_optimized();
let new_pool_1_data = storage::get_backstop_emis_data(&e, &pool_1).unwrap_optimized();
- assert_eq!(new_pool_1_config.eps, 0_2100000);
+ assert_eq!(new_pool_1_config.eps, 0_2101653);
assert_eq!(
new_pool_1_config.expiration,
BACKSTOP_EPOCH + 7 * 24 * 60 * 60
);
- // old config applied up to block timestamp
- assert_eq!(new_pool_1_data.index, 928916);
+ assert_eq!(new_pool_1_data.index, 949491);
assert_eq!(new_pool_1_data.last_time, BACKSTOP_EPOCH);
+
let new_pool_2_config =
storage::get_backstop_emis_config(&e, &pool_2).unwrap_optimized();
let new_pool_2_data = storage::get_backstop_emis_data(&e, &pool_2).unwrap_optimized();
@@ -280,8 +325,9 @@ mod tests {
new_pool_2_config.expiration,
BACKSTOP_EPOCH + 7 * 24 * 60 * 60
);
- assert_eq!(new_pool_2_data.index, 0);
+ assert_eq!(new_pool_2_data.index, 453234);
assert_eq!(new_pool_2_data.last_time, BACKSTOP_EPOCH);
+
let new_pool_3_config =
storage::get_backstop_emis_config(&e, &pool_3).unwrap_optimized();
let new_pool_3_data = storage::get_backstop_emis_data(&e, &pool_3).unwrap_optimized();
@@ -297,34 +343,69 @@ mod tests {
#[test]
#[should_panic(expected = "Error(Contract, #1)")]
- fn test_update_emission_cycle_too_early() {
+ fn test_gulp_emissions_too_soon() {
let e = Env::default();
+ e.budget().reset_unlimited();
+
e.ledger().set(LedgerInfo {
timestamp: BACKSTOP_EPOCH,
protocol_version: 20,
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
- let backstop_id = create_backstop(&e);
- let pool_1 = Address::random(&e);
- let pool_2 = Address::random(&e);
- let pool_3 = Address::random(&e);
+ let backstop = create_backstop(&e);
+ let emitter_distro_time = BACKSTOP_EPOCH - 10;
+ create_emitter(
+ &e,
+ &backstop,
+ &Address::generate(&e),
+ &Address::generate(&e),
+ emitter_distro_time,
+ );
+ let pool_1 = Address::generate(&e);
+ let pool_2 = Address::generate(&e);
+ let pool_3 = Address::generate(&e);
let reward_zone: Vec = vec![&e, pool_1.clone(), pool_2.clone(), pool_3.clone()];
- e.as_contract(&backstop_id, || {
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 1));
+ // setup pool 1 to have ongoing emissions
+ let pool_1_emissions_config = BackstopEmissionConfig {
+ expiration: BACKSTOP_EPOCH + 1000,
+ eps: 0_1000000,
+ };
+ let pool_1_emissions_data = BackstopEmissionsData {
+ index: 887766,
+ last_time: BACKSTOP_EPOCH - 12345,
+ };
+
+ // setup pool 2 to have expired emissions
+ let pool_2_emissions_config = BackstopEmissionConfig {
+ expiration: BACKSTOP_EPOCH - 12345,
+ eps: 0_0500000,
+ };
+ let pool_2_emissions_data = BackstopEmissionsData {
+ index: 453234,
+ last_time: BACKSTOP_EPOCH - 12345,
+ };
+ // setup pool 3 to have no emissions
+ e.as_contract(&backstop, || {
+ storage::set_last_distribution_time(&e, &(emitter_distro_time - 59 * 60));
storage::set_reward_zone(&e, &reward_zone);
+ storage::set_backstop_emis_config(&e, &pool_1, &pool_1_emissions_config);
+ storage::set_backstop_emis_data(&e, &pool_1, &pool_1_emissions_data);
+ storage::set_pool_emissions(&e, &pool_1, 100_123_0000000);
+ storage::set_backstop_emis_config(&e, &pool_2, &pool_2_emissions_config);
+ storage::set_backstop_emis_data(&e, &pool_2, &pool_2_emissions_data);
storage::set_pool_balance(
&e,
&pool_1,
&PoolBalance {
tokens: 300_000_0000000,
- shares: 300_000_0000000,
+ shares: 200_000_0000000,
q4w: 0,
},
);
@@ -333,7 +414,7 @@ mod tests {
&pool_2,
&PoolBalance {
tokens: 200_000_0000000,
- shares: 200_000_0000000,
+ shares: 150_000_0000000,
q4w: 0,
},
);
@@ -342,12 +423,111 @@ mod tests {
&pool_3,
&PoolBalance {
tokens: 500_000_0000000,
- shares: 500_000_0000000,
+ shares: 600_000_0000000,
q4w: 0,
},
);
- update_emission_cycle(&e);
+ gulp_emissions(&e);
+ });
+ }
+
+ /********** gulp_pool_emissions **********/
+
+ #[test]
+ fn test_gulp_pool_emissions() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ e.ledger().set(LedgerInfo {
+ timestamp: BACKSTOP_EPOCH,
+ protocol_version: 20,
+ sequence_number: 0,
+ network_id: Default::default(),
+ base_reserve: 10,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
+ });
+
+ let bombadil = Address::generate(&e);
+ let backstop = create_backstop(&e);
+ let pool_1 = Address::generate(&e);
+ let (_, blnd_token_client) = create_blnd_token(&e, &backstop, &bombadil);
+
+ e.as_contract(&backstop, || {
+ storage::set_pool_emissions(&e, &pool_1, 100_123_0000000);
+
+ gulp_pool_emissions(&e, &pool_1);
+
+ assert_eq!(storage::get_pool_emissions(&e, &pool_1), 0);
+ assert_eq!(
+ blnd_token_client.allowance(&e.current_contract_address(), &pool_1),
+ 100_123_0000000
+ );
+ });
+ }
+
+ #[test]
+ fn test_gulp_pool_emissions_has_allowance() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ e.ledger().set(LedgerInfo {
+ timestamp: BACKSTOP_EPOCH,
+ protocol_version: 20,
+ sequence_number: 0,
+ network_id: Default::default(),
+ base_reserve: 10,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
+ });
+
+ let bombadil = Address::generate(&e);
+ let backstop = create_backstop(&e);
+ let pool_1 = Address::generate(&e);
+ let (_, blnd_token_client) = create_blnd_token(&e, &backstop, &bombadil);
+
+ e.as_contract(&backstop, || {
+ blnd_token_client.approve(&backstop, &pool_1, &1234567, &1000);
+
+ storage::set_pool_emissions(&e, &pool_1, 123_0000000);
+
+ gulp_pool_emissions(&e, &pool_1);
+
+ assert_eq!(storage::get_pool_emissions(&e, &pool_1), 0);
+ assert_eq!(
+ blnd_token_client.allowance(&e.current_contract_address(), &pool_1),
+ 123_1234567
+ );
+ });
+ }
+
+ #[test]
+ #[should_panic(expected = "Error(Contract, #1)")]
+ fn test_gulp_pool_emissions_no_emissions() {
+ let e = Env::default();
+ e.budget().reset_unlimited();
+
+ e.ledger().set(LedgerInfo {
+ timestamp: BACKSTOP_EPOCH,
+ protocol_version: 20,
+ sequence_number: 0,
+ network_id: Default::default(),
+ base_reserve: 10,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
+ });
+
+ let bombadil = Address::generate(&e);
+ let backstop = create_backstop(&e);
+ let pool_1 = Address::generate(&e);
+ create_blnd_token(&e, &backstop, &bombadil);
+
+ e.as_contract(&backstop, || {
+ gulp_pool_emissions(&e, &pool_1);
});
}
@@ -362,20 +542,64 @@ mod tests {
sequence_number: 0,
base_reserve: 10,
network_id: Default::default(),
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
+ let to_add = Address::generate(&e);
e.as_contract(&backstop_id, || {
- add_to_reward_zone(
+ storage::set_pool_balance(
&e,
- to_add.clone(),
- Address::from_contract_id(&BytesN::from_array(&e, &[0u8; 32])),
+ &to_add,
+ &PoolBalance {
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
+ },
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
+
+ add_to_reward_zone(&e, to_add.clone(), Address::generate(&e));
+ let actual_rz = storage::get_reward_zone(&e);
+ let expected_rz: Vec = vec![&e, to_add];
+ assert_eq!(actual_rz, expected_rz);
+ });
+ }
+
+ #[test]
+ #[should_panic(expected = "Error(Contract, #4)")]
+ fn test_add_to_rz_empty_pool_under_backstop_threshold() {
+ let e = Env::default();
+ e.ledger().set(LedgerInfo {
+ timestamp: BACKSTOP_EPOCH,
+ protocol_version: 20,
+ sequence_number: 0,
+ base_reserve: 10,
+ network_id: Default::default(),
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
+ });
+
+ let backstop_id = create_backstop(&e);
+ let to_add = Address::generate(&e);
+
+ e.as_contract(&backstop_id, || {
+ storage::set_pool_balance(
+ &e,
+ &to_add,
+ &PoolBalance {
+ shares: 100_000_0000000,
+ tokens: 75_000_0000000,
+ q4w: 1_000_0000000,
+ },
+ );
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
+
+ add_to_reward_zone(&e, to_add.clone(), Address::generate(&e));
let actual_rz = storage::get_reward_zone(&e);
let expected_rz: Vec = vec![&e, to_add];
assert_eq!(actual_rz, expected_rz);
@@ -391,34 +615,41 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
+ let to_add = Address::generate(&e);
let mut reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- add_to_reward_zone(
+ storage::set_pool_balance(
&e,
- to_add.clone(),
- Address::from_contract_id(&BytesN::from_array(&e, &[0u8; 32])),
+ &to_add,
+ &PoolBalance {
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
+ },
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
+
+ add_to_reward_zone(&e, to_add.clone(), Address::generate(&e));
let actual_rz = storage::get_reward_zone(&e);
reward_zone.push_front(to_add);
assert_eq!(actual_rz, reward_zone);
@@ -434,34 +665,41 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
+ let to_add = Address::generate(&e);
let reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- add_to_reward_zone(
+ storage::set_pool_balance(
&e,
- to_add.clone(),
- Address::from_contract_id(&BytesN::from_array(&e, &[0u8; 32])),
+ &to_add,
+ &PoolBalance {
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
+ },
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
+
+ add_to_reward_zone(&e, to_add.clone(), Address::generate(&e));
});
}
@@ -474,55 +712,56 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
- let to_remove = Address::random(&e);
+ let to_add = Address::generate(&e);
+ let to_remove = Address::generate(&e);
let mut reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
to_remove.clone(), // index 7
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 5 * 24 * 60 * 60));
- storage::set_pool_eps(&e, &to_remove, &1);
+ storage::set_last_distribution_time(&e, &(BACKSTOP_EPOCH - 1 * 24 * 60 * 60));
+ storage::set_pool_emissions(&e, &to_remove, 1);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_001_0000000,
+ q4w: 1_000_0000000,
},
);
storage::set_pool_balance(
&e,
&to_remove,
&PoolBalance {
- shares: 50,
- tokens: 99,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
add_to_reward_zone(&e, to_add.clone(), to_remove.clone());
- let remove_eps = storage::get_pool_eps(&e, &to_remove);
- assert_eq!(remove_eps, 0);
+ let remove_eps = storage::get_pool_emissions(&e, &to_remove);
+ assert_eq!(remove_eps, 1);
let actual_rz = storage::get_reward_zone(&e);
assert_eq!(actual_rz.len(), 10);
reward_zone.set(7, to_add);
@@ -540,58 +779,59 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
- let to_remove = Address::random(&e);
+ let to_add = Address::generate(&e);
+ let to_remove = Address::generate(&e);
let reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
to_remove.clone(), // index 7
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
- storage::set_reward_zone(&e, &reward_zone.clone());
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 24 * 60 * 60));
- storage::set_pool_eps(&e, &to_remove, &1);
+ storage::set_reward_zone(&e, &reward_zone);
+ storage::set_last_distribution_time(&e, &(BACKSTOP_EPOCH - 1 * 24 * 60 * 60));
+ storage::set_pool_emissions(&e, &to_remove, 1);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
storage::set_pool_balance(
&e,
&to_remove,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
add_to_reward_zone(&e, to_add.clone(), to_remove);
});
}
#[test]
- #[should_panic(expected = "Error(Contract, #4)")]
- fn test_add_to_rz_to_remove_not_in_rz() {
+ #[should_panic(expected = "Error(Contract, #1)")]
+ fn test_add_to_rz_swap_distribution_too_long_ago() {
let e = Env::default();
e.ledger().set(LedgerInfo {
timestamp: BACKSTOP_EPOCH,
@@ -599,58 +839,59 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
- let to_remove = Address::random(&e);
+ let to_add = Address::generate(&e);
+ let to_remove = Address::generate(&e);
let reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ to_remove.clone(), // index 7
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 24 * 60 * 60));
- storage::set_pool_eps(&e, &to_remove, &1);
+ storage::set_last_distribution_time(&e, &(BACKSTOP_EPOCH - 1 * 24 * 60 * 60 - 1));
+ storage::set_pool_emissions(&e, &to_remove, 1);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_001_0000000,
+ q4w: 1_000_0000000,
},
);
storage::set_pool_balance(
&e,
&to_remove,
&PoolBalance {
- shares: 50,
- tokens: 99,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
add_to_reward_zone(&e, to_add.clone(), to_remove);
});
}
#[test]
- #[should_panic(expected = "Error(Contract, #1)")]
- fn test_add_to_rz_swap_too_soon_to_distribution() {
+ #[should_panic(expected = "Error(Contract, #4)")]
+ fn test_add_to_rz_to_remove_not_in_rz() {
let e = Env::default();
e.ledger().set(LedgerInfo {
timestamp: BACKSTOP_EPOCH,
@@ -658,52 +899,53 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
- let to_remove = Address::random(&e);
+ let to_add = Address::generate(&e);
+ let to_remove = Address::generate(&e);
let reward_zone: Vec = vec![
&e,
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- to_remove.clone(), // index 7
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 5 * 24 * 60 * 60 + 1));
- storage::set_pool_eps(&e, &to_remove, &1);
+ storage::set_last_distribution_time(&e, &(BACKSTOP_EPOCH - 24 * 60 * 60));
+ storage::set_pool_emissions(&e, &to_remove, 1);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_001_0000000,
+ q4w: 1_000_0000000,
},
);
storage::set_pool_balance(
&e,
&to_remove,
&PoolBalance {
- shares: 50,
- tokens: 99,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
- add_to_reward_zone(&e, to_add, to_remove);
+ add_to_reward_zone(&e, to_add.clone(), to_remove);
});
}
@@ -717,50 +959,51 @@ mod tests {
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
- min_temp_entry_expiration: 10,
- min_persistent_entry_expiration: 10,
- max_entry_expiration: 2000000,
+ min_temp_entry_ttl: 10,
+ min_persistent_entry_ttl: 10,
+ max_entry_ttl: 2000000,
});
let backstop_id = create_backstop(&e);
- let to_add = Address::random(&e);
- let to_remove = Address::random(&e);
+ let to_add = Address::generate(&e);
+ let to_remove = Address::generate(&e);
let reward_zone: Vec = vec![
&e,
- Address::random(&e),
+ Address::generate(&e),
to_remove.clone(),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
+ Address::generate(&e),
to_add.clone(),
- Address::random(&e),
- Address::random(&e),
+ Address::generate(&e),
+ Address::generate(&e),
];
e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
- storage::set_next_emission_cycle(&e, &(BACKSTOP_EPOCH + 5 * 24 * 60 * 60));
- storage::set_pool_eps(&e, &to_remove, &1);
+ storage::set_last_distribution_time(&e, &(BACKSTOP_EPOCH - 24 * 60 * 60));
+ storage::set_pool_emissions(&e, &to_remove, 1);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
- shares: 50,
- tokens: 100,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_001_0000000,
+ q4w: 1_000_0000000,
},
);
storage::set_pool_balance(
&e,
&to_remove,
&PoolBalance {
- shares: 50,
- tokens: 99,
- q4w: 0,
+ shares: 90_000_0000000,
+ tokens: 100_000_0000000,
+ q4w: 1_000_0000000,
},
);
+ storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));
add_to_reward_zone(&e, to_add.clone(), to_remove.clone());
});
diff --git a/backstop/src/emissions/mod.rs b/backstop/src/emissions/mod.rs
index 08dbf136..fa6c629a 100644
--- a/backstop/src/emissions/mod.rs
+++ b/backstop/src/emissions/mod.rs
@@ -5,4 +5,4 @@ mod distributor;
pub use distributor::{update_emission_data, update_emissions};
mod manager;
-pub use manager::{add_to_reward_zone, update_emission_cycle};
+pub use manager::{add_to_reward_zone, gulp_emissions, gulp_pool_emissions};
diff --git a/backstop/src/storage.rs b/backstop/src/storage.rs
index 2e107f74..4179eb9a 100644
--- a/backstop/src/storage.rs
+++ b/backstop/src/storage.rs
@@ -1,5 +1,6 @@
use soroban_sdk::{
- contracttype, unwrap::UnwrapOptimized, vec, Address, Env, Map, Symbol, TryFromVal, Val, Vec,
+ contracttype, unwrap::UnwrapOptimized, vec, Address, Env, IntoVal, Map, Symbol, TryFromVal,
+ Val, Vec,
};
use crate::backstop::{PoolBalance, UserBalance};
@@ -38,6 +39,16 @@ pub struct UserEmissionData {
/********** Storage Key Types **********/
+const EMITTER_KEY: &str = "Emitter";
+const BACKSTOP_TOKEN_KEY: &str = "BToken";
+const POOL_FACTORY_KEY: &str = "PoolFact";
+const BLND_TOKEN_KEY: &str = "BLNDTkn";
+const USDC_TOKEN_KEY: &str = "USDCTkn";
+const LAST_DISTRO_KEY: &str = "LastDist";
+const REWARD_ZONE_KEY: &str = "RZ";
+const DROP_LIST_KEY: &str = "DropList";
+const LP_TOKEN_VAL_KEY: &str = "LPTknVal";
+
#[derive(Clone)]
#[contracttype]
pub struct PoolUserKey {
@@ -51,14 +62,10 @@ pub enum BackstopDataKey {
UserBalance(PoolUserKey),
PoolBalance(Address),
PoolUSDC(Address),
- NextEmis,
- RewardZone,
- PoolEPS(Address),
+ PoolEmis(Address),
BEmisCfg(Address),
BEmisData(Address),
UEmisData(PoolUserKey),
- DropList,
- LPTknVal,
}
/****************************
@@ -66,24 +73,24 @@ pub enum BackstopDataKey {
****************************/
/// Bump the instance rent for the contract
-pub fn bump_instance(e: &Env) {
+pub fn extend_instance(e: &Env) {
e.storage()
.instance()
- .bump(LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
+ .extend_ttl(LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
}
/// Fetch an entry in persistent storage that has a default value if it doesn't exist
-fn get_persistent_default>(
+fn get_persistent_default, V: TryFromVal>(
e: &Env,
- key: &BackstopDataKey,
+ key: &K,
default: V,
bump_threshold: u32,
bump_amount: u32,
) -> V {
- if let Some(result) = e.storage().persistent().get::(key) {
+ if let Some(result) = e.storage().persistent().get::(key) {
e.storage()
.persistent()
- .bump(key, bump_threshold, bump_amount);
+ .extend_ttl(key, bump_threshold, bump_amount);
result
} else {
default
@@ -92,11 +99,29 @@ fn get_persistent_default>(
/********** External Contracts **********/
+/// Fetch the pool factory id
+pub fn get_emitter(e: &Env) -> Address {
+ e.storage()
+ .instance()
+ .get::(&Symbol::new(e, EMITTER_KEY))
+ .unwrap_optimized()
+}
+
+/// Set the pool factory
+///
+/// ### Arguments
+/// * `pool_factory_id` - The ID of the pool factory
+pub fn set_emitter(e: &Env, pool_factory_id: &Address) {
+ e.storage()
+ .instance()
+ .set::(&Symbol::new(e, EMITTER_KEY), pool_factory_id);
+}
+
/// Fetch the pool factory id
pub fn get_pool_factory(e: &Env) -> Address {
e.storage()
.instance()
- .get::(&Symbol::new(e, "PoolFact"))
+ .get::(&Symbol::new(e, POOL_FACTORY_KEY))
.unwrap_optimized()
}
@@ -107,14 +132,14 @@ pub fn get_pool_factory(e: &Env) -> Address {
pub fn set_pool_factory(e: &Env, pool_factory_id: &Address) {
e.storage()
.instance()
- .set::(&Symbol::new(e, "PoolFact"), pool_factory_id);
+ .set::(&Symbol::new(e, POOL_FACTORY_KEY), pool_factory_id);
}
/// Fetch the BLND token id
pub fn get_blnd_token(e: &Env) -> Address {
e.storage()
.instance()
- .get::(&Symbol::new(e, "BLNDTkn"))
+ .get::(&Symbol::new(e, BLND_TOKEN_KEY))
.unwrap_optimized()
}
@@ -125,14 +150,14 @@ pub fn get_blnd_token(e: &Env) -> Address {
pub fn set_blnd_token(e: &Env, blnd_token_id: &Address) {
e.storage()
.instance()
- .set::(&Symbol::new(e, "BLNDTkn"), blnd_token_id);
+ .set::(&Symbol::new(e, BLND_TOKEN_KEY), blnd_token_id);
}
/// Fetch the USDC token id
pub fn get_usdc_token(e: &Env) -> Address {
e.storage()
.instance()
- .get::(&Symbol::new(e, "USDCTkn"))
+ .get::(&Symbol::new(e, USDC_TOKEN_KEY))
.unwrap_optimized()
}
@@ -143,20 +168,22 @@ pub fn get_usdc_token(e: &Env) -> Address {
pub fn set_usdc_token(e: &Env, usdc_token_id: &Address) {
e.storage()
.instance()
- .set::(&Symbol::new(e, "USDCTkn"), usdc_token_id);
+ .set::(&Symbol::new(e, USDC_TOKEN_KEY), usdc_token_id);
}
/// Fetch the backstop token id
pub fn get_backstop_token(e: &Env) -> Address {
e.storage()
.instance()
- .get::(&Symbol::new(e, "BckstpTkn"))
+ .get::(&Symbol::new(e, BACKSTOP_TOKEN_KEY))
.unwrap_optimized()
}
/// Checks if a backstop token is set for the backstop
pub fn has_backstop_token(e: &Env) -> bool {
- e.storage().instance().has(&Symbol::new(e, "BckstpTkn"))
+ e.storage()
+ .instance()
+ .has(&Symbol::new(e, BACKSTOP_TOKEN_KEY))
}
/// Set the backstop token id
@@ -166,7 +193,7 @@ pub fn has_backstop_token(e: &Env) -> bool {
pub fn set_backstop_token(e: &Env, backstop_token_id: &Address) {
e.storage()
.instance()
- .set::(&Symbol::new(e, "BckstpTkn"), backstop_token_id);
+ .set::(&Symbol::new(e, BACKSTOP_TOKEN_KEY), backstop_token_id);
}
/********** User Shares **********/
@@ -242,7 +269,7 @@ pub fn set_pool_balance(e: &Env, pool: &Address, balance: &PoolBalance) {
.set::(&key, balance);
e.storage()
.persistent()
- .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
+ .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
}
/// Fetch the balances for a given pool
@@ -266,16 +293,16 @@ pub fn set_pool_usdc(e: &Env, pool: &Address, balance: &i128) {
.set::(&key, balance);
e.storage()
.persistent()
- .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
+ .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
}
/********** Distribution / Reward Zone **********/
/// Get the timestamp of when the next emission cycle begins
-pub fn get_next_emission_cycle(e: &Env) -> u64 {
+pub fn get_last_distribution_time(e: &Env) -> u64 {
get_persistent_default(
e,
- &BackstopDataKey::NextEmis,
+ &Symbol::new(e, LAST_DISTRO_KEY),
0u64,
LEDGER_THRESHOLD_SHARED,
LEDGER_BUMP_SHARED,
@@ -286,12 +313,12 @@ pub fn get_next_emission_cycle(e: &Env) -> u64 {
///
/// ### Arguments
/// * `timestamp` - The timestamp the distribution window will open
-pub fn set_next_emission_cycle(e: &Env, timestamp: &u64) {
+pub fn set_last_distribution_time(e: &Env, timestamp: &u64) {
e.storage()
.persistent()
- .set::(&BackstopDataKey::NextEmis, timestamp);
- e.storage().persistent().bump(
- &BackstopDataKey::NextEmis,
+ .set::(&Symbol::new(e, LAST_DISTRO_KEY), timestamp);
+ e.storage().persistent().extend_ttl(
+ &Symbol::new(e, LAST_DISTRO_KEY),
LEDGER_THRESHOLD_SHARED,
LEDGER_BUMP_SHARED,
);
@@ -303,7 +330,7 @@ pub fn set_next_emission_cycle(e: &Env, timestamp: &u64) {
pub fn get_reward_zone(e: &Env) -> Vec {
get_persistent_default(
e,
- &BackstopDataKey::RewardZone,
+ &Symbol::new(e, REWARD_ZONE_KEY),
vec![e],
LEDGER_THRESHOLD_SHARED,
LEDGER_BUMP_SHARED,
@@ -317,36 +344,36 @@ pub fn get_reward_zone(e: &Env) -> Vec {
pub fn set_reward_zone(e: &Env, reward_zone: &Vec) {
e.storage()
.persistent()
- .set::>(&BackstopDataKey::RewardZone, reward_zone);
- e.storage().persistent().bump(
- &BackstopDataKey::RewardZone,
+ .set::>(&Symbol::new(e, REWARD_ZONE_KEY), reward_zone);
+ e.storage().persistent().extend_ttl(
+ &Symbol::new(e, REWARD_ZONE_KEY),
LEDGER_THRESHOLD_SHARED,
LEDGER_BUMP_SHARED,
);
}
-/// Get current emissions EPS the backstop is distributing to the pool
+/// Get the current emissions accrued for the pool
///
/// ### Arguments
/// * `pool` - The pool
-pub fn get_pool_eps(e: &Env, pool: &Address) -> i128 {
- let key = BackstopDataKey::PoolEPS(pool.clone());
+pub fn get_pool_emissions(e: &Env, pool: &Address) -> i128 {
+ let key = BackstopDataKey::PoolEmis(pool.clone());
get_persistent_default(e, &key, 0i128, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED)
}
-/// Set the current emissions EPS the backstop is distributing to the pool
+/// Set the current emissions accrued for the pool
///
/// ### Arguments
/// * `pool` - The pool
-/// * `eps` - The eps being distributed to the pool
-pub fn set_pool_eps(e: &Env, pool: &Address, eps: &i128) {
- let key = BackstopDataKey::PoolEPS(pool.clone());
+/// * `emissions` - The number of tokens to distribute to the pool
+pub fn set_pool_emissions(e: &Env, pool: &Address, emissions: i128) {
+ let key = BackstopDataKey::PoolEmis(pool.clone());
e.storage()
.persistent()
- .set::(&key, eps);
+ .set::(&key, &emissions);
e.storage()
.persistent()
- .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
+ .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED);
}
/********** Backstop Depositor Emissions **********/
@@ -357,7 +384,7 @@ pub fn set_pool_eps(e: &Env, pool: &Address, eps: &i128) {
/// * `pool` - The pool
pub fn get_backstop_emis_config(e: &Env, pool: &Address) -> Option {
let key = BackstopDataKey::BEmisCfg(pool.clone());
- get_persistent_default::