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::>( + get_persistent_default::>( e, &key, None, @@ -366,15 +393,6 @@ pub fn get_backstop_emis_config(e: &Env, pool: &Address) -> Option bool { - let key = BackstopDataKey::BEmisCfg(pool.clone()); - e.storage().persistent().has::(&key) -} - /// Set the pool's backstop emissions config /// /// ### Arguments @@ -397,7 +415,7 @@ pub fn set_backstop_emis_config( /// * `pool` - The pool pub fn get_backstop_emis_data(e: &Env, pool: &Address) -> Option { let key = BackstopDataKey::BEmisData(pool.clone()); - get_persistent_default::>( + get_persistent_default::>( e, &key, None, @@ -428,7 +446,7 @@ pub fn get_user_emis_data(e: &Env, pool: &Address, user: &Address) -> Option>( + get_persistent_default::>( e, &key, None, @@ -464,7 +482,7 @@ pub fn set_user_emis_data( pub fn get_drop_list(e: &Env) -> Map { e.storage() .temporary() - .get::>(&BackstopDataKey::DropList) + .get::>(&Symbol::new(&e, DROP_LIST_KEY)) .unwrap_optimized() } @@ -475,9 +493,9 @@ pub fn get_drop_list(e: &Env) -> Map { pub fn set_drop_list(e: &Env, drop_list: &Map) { e.storage() .temporary() - .set::>(&BackstopDataKey::DropList, drop_list); - e.storage().temporary().bump( - &BackstopDataKey::DropList, + .set::>(&Symbol::new(&e, DROP_LIST_KEY), drop_list); + e.storage().temporary().extend_ttl( + &Symbol::new(&e, DROP_LIST_KEY), LEDGER_THRESHOLD_USER, LEDGER_BUMP_USER, ); @@ -487,14 +505,14 @@ pub fn set_drop_list(e: &Env, drop_list: &Map) { /// Get the last updated token value for the LP pool pub fn get_lp_token_val(e: &Env) -> (i128, i128) { - e.storage().persistent().bump( - &BackstopDataKey::LPTknVal, + e.storage().persistent().extend_ttl( + &Symbol::new(&e, LP_TOKEN_VAL_KEY), LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED, ); e.storage() .persistent() - .get::(&BackstopDataKey::LPTknVal) + .get::(&Symbol::new(&e, LP_TOKEN_VAL_KEY)) .unwrap_optimized() } @@ -505,9 +523,9 @@ pub fn get_lp_token_val(e: &Env) -> (i128, i128) { pub fn set_lp_token_val(e: &Env, share_val: &(i128, i128)) { e.storage() .persistent() - .set::(&BackstopDataKey::LPTknVal, share_val); - e.storage().persistent().bump( - &BackstopDataKey::LPTknVal, + .set::(&Symbol::new(&e, LP_TOKEN_VAL_KEY), share_val); + e.storage().persistent().extend_ttl( + &Symbol::new(&e, LP_TOKEN_VAL_KEY), LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED, ); diff --git a/backstop/src/testutils.rs b/backstop/src/testutils.rs index 3f7041dd..e21967f7 100644 --- a/backstop/src/testutils.rs +++ b/backstop/src/testutils.rs @@ -8,11 +8,14 @@ use crate::{ }; use soroban_sdk::{ - testutils::Address as _, unwrap::UnwrapOptimized, vec, Address, Env, IntoVal, Vec, + testutils::{Address as _, Ledger, LedgerInfo}, + unwrap::UnwrapOptimized, + vec, Address, Env, IntoVal, Vec, }; use sep_41_token::testutils::{MockTokenClient, MockTokenWASM}; +use emitter::{EmitterClient, EmitterContract}; use mock_pool_factory::{MockPoolFactory, MockPoolFactoryClient}; pub(crate) fn create_backstop(e: &Env) -> Address { @@ -20,7 +23,7 @@ pub(crate) fn create_backstop(e: &Env) -> Address { } pub(crate) fn create_token<'a>(e: &Env, admin: &Address) -> (Address, MockTokenClient<'a>) { - let contract_address = Address::random(e); + let contract_address = Address::generate(e); e.register_contract_wasm(&contract_address, MockTokenWASM); let client = MockTokenClient::new(e, &contract_address); client.initialize(&admin, &7, &"unit".into_val(e), &"test".into_val(e)); @@ -80,6 +83,44 @@ pub(crate) fn create_mock_pool_factory<'a>( ) } +pub(crate) fn create_emitter<'a>( + e: &Env, + backstop: &Address, + backstop_token: &Address, + blnd_token: &Address, + emitter_last_distro: u64, +) -> (Address, EmitterClient<'a>) { + let contract_address = e.register_contract(None, EmitterContract {}); + + let prev_timestamp = e.ledger().timestamp(); + e.ledger().set(LedgerInfo { + timestamp: emitter_last_distro, + 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, + }); + e.as_contract(backstop, || { + storage::set_emitter(e, &contract_address); + }); + let client = EmitterClient::new(e, &contract_address); + client.initialize(&blnd_token, &backstop, &backstop_token); + e.ledger().set(LedgerInfo { + timestamp: prev_timestamp, + 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, + }); + (contract_address.clone(), client) +} + /// Deploy a test Comet LP pool of 80% BLND / 20% USDC and set it as the backstop token. /// /// Initializes the pool with the following settings: @@ -93,7 +134,7 @@ pub(crate) fn create_comet_lp_pool<'a>( blnd_token: &Address, usdc_token: &Address, ) -> (Address, CometClient<'a>) { - let contract_address = Address::random(e); + let contract_address = Address::generate(e); e.register_contract_wasm(&contract_address, COMET_WASM); let client = CometClient::new(e, &contract_address); @@ -105,7 +146,7 @@ pub(crate) fn create_comet_lp_pool<'a>( blnd_client.approve(&admin, &contract_address, &2_000_0000000, &exp_ledger); usdc_client.approve(&admin, &contract_address, &2_000_0000000, &exp_ledger); - client.init(&Address::random(e), &admin); + client.init(&Address::generate(e), &admin); client.bundle_bind( &vec![e, blnd_token.clone(), usdc_token.clone()], &vec![e, 1_000_0000000, 25_0000000], diff --git a/comet.wasm b/comet.wasm index a6a14345..bd2bc139 100644 Binary files a/comet.wasm and b/comet.wasm differ diff --git a/emitter/Cargo.toml b/emitter/Cargo.toml index 8f21f2b5..94496f55 100644 --- a/emitter/Cargo.toml +++ b/emitter/Cargo.toml @@ -19,5 +19,4 @@ sep-41-token = { workspace = true } [dev_dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } -backstop = { path = "../backstop", features = ["testutils"] } sep-41-token = { workspace = true, features = ["testutils"] } diff --git a/emitter/src/backstop_manager.rs b/emitter/src/backstop_manager.rs new file mode 100644 index 00000000..bc1f045a --- /dev/null +++ b/emitter/src/backstop_manager.rs @@ -0,0 +1,603 @@ +use sep_41_token::TokenClient; +use soroban_sdk::{contracttype, panic_with_error, Address, Env}; + +use crate::{emitter, storage, EmitterError}; + +#[derive(Clone)] +#[contracttype] +pub struct Swap { + pub new_backstop: Address, + pub new_backstop_token: Address, + pub unlock_time: u64, +} + +/// Require that the new backstop is larger than the backstop +/// +/// Panics otherwise +fn is_new_backstop_is_larger(e: &Env, new_backstop: &Address, backstop: &Address) -> bool { + let backstop_token = storage::get_backstop_token(e); + let backstop_token_client = TokenClient::new(e, &backstop_token); + + let backstop_balance = backstop_token_client.balance(&backstop); + let new_backstop_balance = backstop_token_client.balance(&new_backstop); + return new_backstop_balance > backstop_balance; +} + +/// Perform a backstop swap +pub fn execute_queue_swap_backstop( + e: &Env, + new_backstop: &Address, + new_backstop_token: &Address, +) -> Swap { + // verify no swap is already queued + if storage::get_queued_swap(e).is_some() { + panic_with_error!(e, EmitterError::SwapAlreadyExists); + } + + let backstop = storage::get_backstop(e); + if !is_new_backstop_is_larger(e, new_backstop, &backstop) { + panic_with_error!(e, EmitterError::InsufficientBackstopSize); + } + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: e.ledger().timestamp() + 31 * 24 * 60 * 60, + }; + storage::set_queued_swap(e, &swap); + swap +} + +/// Cancel a backstop swap if it has not maintained a higher balance than the current backstop +pub fn execute_cancel_swap_backstop(e: &Env) -> Swap { + let swap = storage::get_queued_swap(e) + .unwrap_or_else(|| panic_with_error!(e, EmitterError::SwapNotQueued)); + + let backstop = storage::get_backstop(e); + if is_new_backstop_is_larger(e, &swap.new_backstop, &backstop) { + panic_with_error!(e, EmitterError::SwapCannotBeCanceled); + } + + storage::del_queued_swap(e); + swap +} + +/// Perform a swap from the queue if it has been unlocked and the new backstop has maintained a higher balance than the current backstop +pub fn execute_swap_backstop(e: &Env) -> Swap { + let swap = storage::get_queued_swap(e) + .unwrap_or_else(|| panic_with_error!(e, EmitterError::SwapNotQueued)); + + if swap.unlock_time > e.ledger().timestamp() { + panic_with_error!(e, EmitterError::SwapNotUnlocked); + } + + let backstop = storage::get_backstop(e); + if !is_new_backstop_is_larger(e, &swap.new_backstop, &backstop) { + panic_with_error!(e, EmitterError::InsufficientBackstopSize); + } + + // distribute before swapping to ensure the old backstop gets their tokens + emitter::execute_distribute(e, &backstop); + + // swap backstop and token + storage::set_last_fork(e, e.ledger().sequence()); + storage::del_queued_swap(e); + storage::set_backstop(e, &swap.new_backstop); + storage::set_backstop_token(e, &swap.new_backstop_token); + + // start distribution for new backstop + storage::set_last_distro_time(e, &swap.new_backstop, e.ledger().timestamp()); + + swap +} + +#[cfg(test)] +mod tests { + + use crate::{constants::SCALAR_7, storage, testutils::create_emitter}; + + use super::*; + use sep_41_token::testutils::MockTokenClient; + use soroban_sdk::testutils::{Address as _, Ledger, LedgerInfo}; + + /********** execute_queue_swap_backstop **********/ + + #[test] + fn test_execute_queue_swap_backstop() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + + execute_queue_swap_backstop(&e, &new_backstop, &new_backstop_token); + + // verify no swap occurred + assert_eq!(storage::get_backstop(&e), backstop); + assert_eq!(storage::get_backstop_token(&e), backstop_token); + assert_eq!(storage::get_last_fork(&e), 123); + + // verify swap is queued + let swap = storage::get_queued_swap(&e); + assert!(swap.is_some()); + let swap = swap.unwrap(); + assert_eq!(swap.new_backstop, new_backstop); + assert_eq!(swap.new_backstop_token, new_backstop_token); + assert_eq!(swap.unlock_time, 2678400 + 12345); // 31 days + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #30)")] + fn test_execute_queue_swap_backstop_insufficient_funds() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_000 * SCALAR_7)); + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + + execute_queue_swap_backstop(&e, &new_backstop, &new_backstop_token); + assert!(false); // should panic + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #60)")] + fn test_execute_queue_swap_backstop_already_exists() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + let swap = Swap { + new_backstop: Address::generate(&e), + new_backstop_token: Address::generate(&e), + unlock_time: 0, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_queue_swap_backstop(&e, &new_backstop, &new_backstop_token); + assert!(false); // should panic + }); + } + + /********** execute_cancel_swap_backstop **********/ + + #[test] + fn test_execute_cancel_swap_backstop() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_000 * SCALAR_7)); + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: 12345 + 1000, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_cancel_swap_backstop(&e); + + // verify no swap occurred + assert_eq!(storage::get_backstop(&e), backstop); + assert_eq!(storage::get_backstop_token(&e), backstop_token); + assert_eq!(storage::get_last_fork(&e), 123); + + // verify swap is removed + let swap = storage::get_queued_swap(&e); + assert!(swap.is_none()); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #80)")] + fn test_execute_cancel_swap_backstop_valid_swap() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: 12345 + 1000, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_cancel_swap_backstop(&e); + assert!(false); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #50)")] + fn test_execute_cancel_swap_backstop_none_queued() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 50, + 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 emitter = create_emitter(&e); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_000 * SCALAR_7)); + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 1000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + + execute_cancel_swap_backstop(&e); + assert!(false); + }); + } + + /********** execute_swap_backstop **********/ + + #[test] + fn test_execute_swap_backstop() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 500, + 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 emitter = create_emitter(&e); + + let blnd_token = e.register_stellar_asset_contract(emitter.clone()); + let blnd_token_client = MockTokenClient::new(&e, &blnd_token); + + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: 12345, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 10000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_blnd_token(&e, &blnd_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_swap_backstop(&e); + + // verify swap occurred + assert_eq!(storage::get_backstop(&e), new_backstop); + assert_eq!(storage::get_backstop_token(&e), new_backstop_token); + assert_eq!(storage::get_last_fork(&e), 500); + + // verify swap is removed + let swap = storage::get_queued_swap(&e); + assert!(swap.is_none()); + + // verify old backstop was distributed and new backstop distribution begins + assert_eq!(storage::get_last_distro_time(&e, &backstop), 12345); + assert_eq!(storage::get_last_distro_time(&e, &new_backstop), 12345); + assert_eq!(blnd_token_client.balance(&backstop), 2345 * SCALAR_7); + assert_eq!(blnd_token_client.balance(&new_backstop), 0); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #70)")] + fn test_execute_swap_backstop_not_unlocked() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 500, + 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 emitter = create_emitter(&e); + + let blnd_token = e.register_stellar_asset_contract(emitter.clone()); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: 12345 + 1, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 10000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_blnd_token(&e, &blnd_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_swap_backstop(&e); + assert!(false); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #50)")] + fn test_execute_swap_backstop_no_queue() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 500, + 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 emitter = create_emitter(&e); + + let blnd_token = e.register_stellar_asset_contract(emitter.clone()); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 10000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_blnd_token(&e, &blnd_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + + execute_swap_backstop(&e); + assert!(false); + }); + } + + #[test] + #[should_panic(expected = "Error(Contract, #30)")] + fn test_execute_swap_backstop_insufficient_funds() { + let e = Env::default(); + e.mock_all_auths(); + + e.ledger().set(LedgerInfo { + timestamp: 12345, + protocol_version: 20, + sequence_number: 500, + 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 emitter = create_emitter(&e); + + let blnd_token = e.register_stellar_asset_contract(emitter.clone()); + let backstop = Address::generate(&e); + let new_backstop = Address::generate(&e); + + let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); + let backstop_token_client = MockTokenClient::new(&e, &backstop_token); + let new_backstop_token = Address::generate(&e); + + backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); + backstop_token_client.mint(&new_backstop, &(1_000_000 * SCALAR_7)); + + let swap = Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: new_backstop_token.clone(), + unlock_time: 12345, + }; + + e.as_contract(&emitter, || { + storage::set_last_distro_time(&e, &backstop, 10000); + storage::set_backstop(&e, &backstop); + storage::set_backstop_token(&e, &backstop_token); + storage::set_blnd_token(&e, &blnd_token); + storage::set_drop_status(&e, &backstop); + storage::set_last_fork(&e, 123); + storage::set_queued_swap(&e, &swap); + + execute_swap_backstop(&e); + assert!(false); + }); + } +} diff --git a/emitter/src/contract.rs b/emitter/src/contract.rs index a49dad88..4dddc740 100644 --- a/emitter/src/contract.rs +++ b/emitter/src/contract.rs @@ -1,5 +1,7 @@ -use crate::{emitter, errors::EmitterError, storage}; -use soroban_sdk::{contract, contractclient, contractimpl, panic_with_error, Address, Env, Symbol}; +use crate::{backstop_manager, emitter, errors::EmitterError, storage}; +use soroban_sdk::{ + contract, contractclient, contractimpl, panic_with_error, Address, Env, Map, Symbol, +}; /// ### Emitter /// @@ -12,57 +14,80 @@ pub trait Emitter { /// Initialize the Emitter /// /// ### Arguments - /// * `backstop_id` - The backstop module Address ID - /// * `blnd_token_id` - The Blend token Address ID - fn initialize(e: Env, backstop: Address, blnd_token_id: Address); + /// * `blnd_token` - The Blend token Address the Emitter will distribute + /// * `backstop` - The backstop module address to emit to + /// * `backstop_token` - The token the backstop takes deposits in + fn initialize(e: Env, blnd_token: Address, backstop: Address, backstop_token: Address); /// Distributes BLND tokens to the listed backstop module /// /// Returns the amount of BLND tokens distributed - /// - /// ### Errors - /// If the caller is not the listed backstop module fn distribute(e: Env) -> i128; + /// Fetch the last time the Emitter distributed to the backstop module + /// + /// ### Arguments + /// * `backstop` - The backstop module Address ID + fn get_last_distro(e: Env, backstop_id: Address) -> u64; + /// Fetch the current backstop fn get_backstop(e: Env) -> Address; - /// Switches the listed backstop module to one with more effective backstop deposits - /// - /// Returns OK or an error + /// Queues up a swap of the listed backstop module and token to new addresses. /// /// ### Arguments - /// * `new_backstop_id` - The Address ID of the new backstop module + /// * `new_backstop` - The Address of the new backstop module + /// * `new_backstop_token` - The address of the new backstop token + /// + /// ### Errors + /// If the input contract does not have more backstop deposits than the listed backstop module of the + /// current backstop token. + fn queue_swap_backstop(e: Env, new_backstop: Address, new_backstop_token: Address); + + /// Fetch the queued backstop swap, or None if nothing is queued. + fn get_queued_swap(e: Env) -> Option; + + /// Verifies that a queued swap still meets the requirements to be executed. If not, + /// the queued swap is cancelled and must be recreated. + /// + /// ### Errors + /// If the queued swap is still valid. + fn cancel_swap_backstop(e: Env); + + /// Executes a queued swap of the listed backstop module to one with more effective backstop deposits /// /// ### Errors - /// If the input contract does not have more backstop deposits than the listed backstop module - fn swap_backstop(e: Env, new_backstop_id: Address); + /// If the input contract does not have more backstop deposits than the listed backstop module, + /// or if the queued swap has not been unlocked. + fn swap_backstop(e: Env); - /// Distributes initial BLND post-backstop swap or protocol launch + /// Distributes initial BLND after a new backstop is set /// - /// Returns OK or an error + /// ### Arguments + /// * `list` - The list of address and amounts to distribute too /// /// ### Errors - /// If drop has already been called for this backstop - fn drop(e: Env); + /// If drop has already been called for the backstop, the backstop is not the caller, + /// or the list exceeds the drop amount maximum. + fn drop(e: Env, list: Map); } #[contractimpl] impl Emitter for EmitterContract { - fn initialize(e: Env, backstop: Address, blnd_token_id: Address) { - storage::bump_instance(&e); - if storage::has_backstop(&e) { + fn initialize(e: Env, blnd_token: Address, backstop: Address, backstop_token: Address) { + storage::extend_instance(&e); + if storage::has_blnd_token(&e) { panic_with_error!(&e, EmitterError::AlreadyInitialized) } + storage::set_blnd_token(&e, &blnd_token); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_token_id); - storage::set_last_fork(&e, 0); // We set the block 45 days in the past to allow for an immediate initial drop - storage::set_last_distro_time(&e, &(e.ledger().timestamp() - 7 * 24 * 60 * 60)); + storage::set_backstop_token(&e, &backstop_token); + storage::set_last_distro_time(&e, &backstop, e.ledger().timestamp()); } fn distribute(e: Env) -> i128 { - storage::bump_instance(&e); + storage::extend_instance(&e); let backstop_address = storage::get_backstop(&e); let distribution_amount = emitter::execute_distribute(&e, &backstop_address); @@ -74,22 +99,44 @@ impl Emitter for EmitterContract { distribution_amount } + fn get_last_distro(e: Env, backstop_id: Address) -> u64 { + storage::get_last_distro_time(&e, &backstop_id) + } + fn get_backstop(e: Env) -> Address { storage::get_backstop(&e) } - fn swap_backstop(e: Env, new_backstop_id: Address) { - storage::bump_instance(&e); - emitter::execute_swap_backstop(&e, new_backstop_id.clone()); + fn queue_swap_backstop(e: Env, new_backstop: Address, new_backstop_token: Address) { + storage::extend_instance(&e); + let swap = + backstop_manager::execute_queue_swap_backstop(&e, &new_backstop, &new_backstop_token); + + e.events().publish((Symbol::new(&e, "q_swap"),), swap); + } + + fn get_queued_swap(e: Env) -> Option { + storage::get_queued_swap(&e) + } + + fn cancel_swap_backstop(e: Env) { + storage::extend_instance(&e); + let swap = backstop_manager::execute_cancel_swap_backstop(&e); + + e.events().publish((Symbol::new(&e, "del_swap"),), swap); + } + + fn swap_backstop(e: Env) { + storage::extend_instance(&e); + let swap = backstop_manager::execute_swap_backstop(&e); - e.events() - .publish((Symbol::new(&e, "swap"),), (new_backstop_id,)); + e.events().publish((Symbol::new(&e, "swap"),), swap); } - fn drop(e: Env) { - storage::bump_instance(&e); - let drop_list = emitter::execute_drop(&e); + fn drop(e: Env, list: Map) { + storage::extend_instance(&e); + emitter::execute_drop(&e, &list); - e.events().publish((Symbol::new(&e, "drop"),), drop_list); + e.events().publish((Symbol::new(&e, "drop"),), list); } } diff --git a/emitter/src/dependencies/mod.rs b/emitter/src/dependencies/mod.rs deleted file mode 100644 index d6d77753..00000000 --- a/emitter/src/dependencies/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod backstop; -pub use backstop::Client as BackstopClient; -#[cfg(any(test, feature = "testutils"))] -pub use backstop::{BackstopDataKey, WASM as BACKSTOP_WASM}; diff --git a/emitter/src/emitter.rs b/emitter/src/emitter.rs index 64e90415..ddffa380 100644 --- a/emitter/src/emitter.rs +++ b/emitter/src/emitter.rs @@ -1,41 +1,27 @@ -use crate::{constants::SCALAR_7, dependencies::BackstopClient, errors::EmitterError, storage}; -use sep_41_token::{StellarAssetClient, TokenClient}; +use crate::{constants::SCALAR_7, errors::EmitterError, storage}; +use sep_41_token::StellarAssetClient; use soroban_sdk::{panic_with_error, Address, Env, Map}; /// Perform a distribution pub fn execute_distribute(e: &Env, backstop: &Address) -> i128 { let timestamp = e.ledger().timestamp(); - let seconds_since_last_distro = timestamp - storage::get_last_distro_time(e); + let seconds_since_last_distro = timestamp - storage::get_last_distro_time(e, backstop); // Blend tokens are distributed at a rate of 1 token per second let distribution_amount = (seconds_since_last_distro as i128) * SCALAR_7; - storage::set_last_distro_time(e, ×tamp); + storage::set_last_distro_time(e, backstop, timestamp); - let blend_id = storage::get_blend_id(e); - let blend_client = StellarAssetClient::new(e, &blend_id); - blend_client.mint(backstop, &distribution_amount); + let blnd_id = storage::get_blnd_token(e); + let blnd_client = StellarAssetClient::new(e, &blnd_id); + blnd_client.mint(backstop, &distribution_amount); distribution_amount } -/// Perform a backstop swap -pub fn execute_swap_backstop(e: &Env, new_backstop_id: Address) { - let backstop = storage::get_backstop(e); - let backstop_token = BackstopClient::new(e, &backstop).backstop_token(); - let backstop_token_client = TokenClient::new(e, &backstop_token); - - let backstop_balance = backstop_token_client.balance(&backstop); - let new_backstop_balance = backstop_token_client.balance(&new_backstop_id); - if new_backstop_balance > backstop_balance { - storage::set_backstop(e, &new_backstop_id); - storage::set_last_fork(e, e.ledger().sequence()); - } else { - panic_with_error!(e, EmitterError::InsufficientBackstopSize); - } -} - /// Perform drop BLND distribution -pub fn execute_drop(e: &Env) -> Map { +pub fn execute_drop(e: &Env, list: &Map) { let backstop = storage::get_backstop(e); + backstop.require_auth(); + if storage::get_drop_status(e, &backstop) { panic_with_error!(e, EmitterError::BadDrop); } @@ -44,11 +30,8 @@ pub fn execute_drop(e: &Env) -> Map { panic_with_error!(e, EmitterError::BadDrop); } - let backstop = storage::get_backstop(e); - let backstop_client = BackstopClient::new(e, &backstop); - let drop_list: Map = backstop_client.drop_list(); let mut drop_amount = 0; - for (_, amt) in drop_list.iter() { + for (_, amt) in list.iter() { drop_amount += amt; } // drop cannot be more than 50 million tokens @@ -56,22 +39,18 @@ pub fn execute_drop(e: &Env) -> Map { panic_with_error!(e, EmitterError::BadDrop); } - let blnd_id = storage::get_blend_id(e); + let blnd_id = storage::get_blnd_token(e); let blnd_client = StellarAssetClient::new(e, &blnd_id); - for (addr, amt) in drop_list.iter() { + for (addr, amt) in list.iter() { blnd_client.mint(&addr, &amt); } storage::set_drop_status(e, &backstop); - drop_list } #[cfg(test)] mod tests { - use crate::{ - storage, - testutils::{create_backstop, create_emitter}, - }; + use crate::{storage, testutils::create_emitter}; use super::*; use sep_41_token::testutils::MockTokenClient; @@ -91,117 +70,26 @@ mod tests { sequence_number: 50, 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 emitter = create_emitter(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); let blnd_id = e.register_stellar_asset_contract(emitter.clone()); let blnd_client = MockTokenClient::new(&e, &blnd_id); e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); + storage::set_last_distro_time(&e, &backstop, 1000); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_id); + storage::set_blnd_token(&e, &blnd_id); let result = execute_distribute(&e, &backstop); assert_eq!(result, 11345_0000000); assert_eq!(blnd_client.balance(&backstop), 11345_0000000); - assert_eq!(storage::get_last_distro_time(&e), 12345); - }); - } - - #[test] - fn test_swap_backstop() { - let e = Env::default(); - e.mock_all_auths(); - - e.ledger().set(LedgerInfo { - timestamp: 12345, - protocol_version: 20, - sequence_number: 50, - network_id: Default::default(), - base_reserve: 10, - min_temp_entry_expiration: 10, - min_persistent_entry_expiration: 10, - max_entry_expiration: 2000000, - }); - - let bombadil = Address::random(&e); - let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); - let new_backstop = Address::random(&e); - - let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); - let backstop_token_client = MockTokenClient::new(&e, &backstop_token); - - backstop_client.initialize( - &backstop_token, - &Address::random(&e), - &Address::random(&e), - &Address::random(&e), - &Map::new(&e), - ); - - backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); - backstop_token_client.mint(&new_backstop, &(1_000_001 * SCALAR_7)); - - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); - storage::set_backstop(&e, &backstop); - storage::set_drop_status(&e, &backstop); - - execute_swap_backstop(&e, new_backstop.clone()); - assert_eq!(storage::get_backstop(&e), new_backstop); - assert_eq!(storage::get_drop_status(&e, &new_backstop), false); - }); - } - - #[test] - #[should_panic(expected = "Error(Contract, #30)")] - fn test_swap_backstop_not_enough() { - let e = Env::default(); - e.mock_all_auths(); - - e.ledger().set(LedgerInfo { - timestamp: 12345, - protocol_version: 20, - sequence_number: 50, - network_id: Default::default(), - base_reserve: 10, - min_temp_entry_expiration: 10, - min_persistent_entry_expiration: 10, - max_entry_expiration: 2000000, - }); - - let bombadil = Address::random(&e); - let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); - let new_backstop = Address::random(&e); - - let backstop_token = e.register_stellar_asset_contract(bombadil.clone()); - let backstop_token_client = MockTokenClient::new(&e, &backstop_token); - - backstop_client.initialize( - &backstop_token, - &Address::random(&e), - &Address::random(&e), - &Address::random(&e), - &Map::new(&e), - ); - - backstop_token_client.mint(&backstop, &(1_000_000 * SCALAR_7)); - backstop_token_client.mint(&new_backstop, &(1_000_000 * SCALAR_7)); - - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); - storage::set_backstop(&e, &backstop); - - execute_swap_backstop(&e, new_backstop.clone()); - assert!(false, "Should have panicked"); + assert_eq!(storage::get_last_distro_time(&e, &backstop), 12345); }); } @@ -216,15 +104,15 @@ mod tests { sequence_number: 5000000, 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 frodo = Address::random(&e); - let samwise = Address::random(&e); + let frodo = Address::generate(&e); + let samwise = Address::generate(&e); let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); + let backstop = Address::generate(&e); let blnd_id = e.register_stellar_asset_contract(emitter.clone()); let blnd_client = MockTokenClient::new(&e, &blnd_id); @@ -234,23 +122,14 @@ mod tests { (samwise.clone(), 30_000_000 * SCALAR_7) ]; - backstop_client.initialize( - &Address::random(&e), - &blnd_id, - &Address::random(&e), - &Address::random(&e), - &drop_list, - ); - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); + storage::set_last_distro_time(&e, &backstop, 1000); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_id); + storage::set_blnd_token(&e, &blnd_id); storage::set_last_fork(&e, 4000000); - let list = execute_drop(&e); + execute_drop(&e, &drop_list); assert_eq!(storage::get_drop_status(&e, &backstop), true); - assert_eq!(list.len(), 2); assert_eq!(blnd_client.balance(&frodo), 20_000_000 * SCALAR_7); assert_eq!(blnd_client.balance(&samwise), 30_000_000 * SCALAR_7); }); @@ -268,15 +147,15 @@ mod tests { sequence_number: 5000000, 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 frodo = Address::random(&e); - let samwise = Address::random(&e); + let frodo = Address::generate(&e); + let samwise = Address::generate(&e); let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); + let backstop = Address::generate(&e); let blnd_id = e.register_stellar_asset_contract(emitter.clone()); let drop_list = map![ @@ -285,22 +164,14 @@ mod tests { (samwise.clone(), 30_000_000 * SCALAR_7) ]; - backstop_client.initialize( - &Address::random(&e), - &blnd_id, - &Address::random(&e), - &Address::random(&e), - &drop_list, - ); - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); + storage::set_last_distro_time(&e, &backstop, 1000); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_id); + storage::set_blnd_token(&e, &blnd_id); storage::set_drop_status(&e, &backstop); storage::set_last_fork(&e, 4000000); - execute_drop(&e); + execute_drop(&e, &drop_list); assert_eq!(storage::get_drop_status(&e, &backstop), true); }); } @@ -317,15 +188,15 @@ mod tests { sequence_number: 5000000, 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 frodo = Address::random(&e); - let samwise = Address::random(&e); + let frodo = Address::generate(&e); + let samwise = Address::generate(&e); let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); + let backstop = Address::generate(&e); let blnd_id = e.register_stellar_asset_contract(emitter.clone()); let drop_list = map![ @@ -334,21 +205,13 @@ mod tests { (samwise.clone(), 30_000_001 * SCALAR_7) ]; - backstop_client.initialize( - &Address::random(&e), - &blnd_id, - &Address::random(&e), - &Address::random(&e), - &drop_list, - ); - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); + storage::set_last_distro_time(&e, &backstop, 1000); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_id); + storage::set_blnd_token(&e, &blnd_id); storage::set_last_fork(&e, 4000000); - execute_drop(&e); + execute_drop(&e, &drop_list); assert_eq!(storage::get_drop_status(&e, &backstop), false); }); } @@ -365,16 +228,16 @@ mod tests { sequence_number: 5000000, 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 frodo = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let frodo = Address::generate(&e); + let samwise = Address::generate(&e); let emitter = create_emitter(&e); - let (backstop, backstop_client) = create_backstop(&e); + let backstop = Address::generate(&e); let blnd_id = e.register_stellar_asset_contract(bombadil.clone()); let drop_list = map![ @@ -383,21 +246,13 @@ mod tests { (samwise.clone(), 30_000_000 * SCALAR_7) ]; - backstop_client.initialize( - &Address::random(&e), - &blnd_id, - &Address::random(&e), - &Address::random(&e), - &drop_list, - ); - e.as_contract(&emitter, || { - storage::set_last_distro_time(&e, &1000); + storage::set_last_distro_time(&e, &backstop, 1000); storage::set_backstop(&e, &backstop); - storage::set_blend_id(&e, &blnd_id); + storage::set_blnd_token(&e, &blnd_id); storage::set_last_fork(&e, 5000000); - execute_drop(&e); + execute_drop(&e, &drop_list); }); } } diff --git a/emitter/src/errors.rs b/emitter/src/errors.rs index 41d8b3ef..4e40edbf 100644 --- a/emitter/src/errors.rs +++ b/emitter/src/errors.rs @@ -8,4 +8,8 @@ pub enum EmitterError { NotAuthorized = 20, InsufficientBackstopSize = 30, BadDrop = 40, + SwapNotQueued = 50, + SwapAlreadyExists = 60, + SwapNotUnlocked = 70, + SwapCannotBeCanceled = 80, } diff --git a/emitter/src/lib.rs b/emitter/src/lib.rs index e48f55cb..c35f5de6 100644 --- a/emitter/src/lib.rs +++ b/emitter/src/lib.rs @@ -3,6 +3,7 @@ #[cfg(any(test, feature = "testutils"))] extern crate std; +mod backstop_manager; mod constants; mod contract; mod emitter; @@ -10,8 +11,7 @@ mod errors; mod storage; mod testutils; -mod dependencies; - +pub use backstop_manager::Swap; pub use contract::*; pub use errors::EmitterError; pub use storage::EmitterDataKey; diff --git a/emitter/src/storage.rs b/emitter/src/storage.rs index 9b595bf6..59c07249 100644 --- a/emitter/src/storage.rs +++ b/emitter/src/storage.rs @@ -1,86 +1,138 @@ -use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env}; +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env, Symbol}; + +use crate::backstop_manager::Swap; pub(crate) const LEDGER_THRESHOLD_SHARED: u32 = 172800; // ~ 10 days pub(crate) const LEDGER_BUMP_SHARED: u32 = 241920; // ~ 14 days /********** Storage **********/ +const BACKSTOP_KEY: &str = "Backstop"; +const BACKSTOP_TOKEN_KEY: &str = "BToken"; +const BLND_TOKEN_KEY: &str = "BLNDTkn"; +const LAST_FORK_KEY: &str = "LastFork"; +const SWAP_KEY: &str = "Swap"; + // Emitter Data Keys #[derive(Clone)] #[contracttype] pub enum EmitterDataKey { - // The address of the backstop module contract - Backstop, - /// TODO: Delete after address <-> bytesN support, - BstopId, - // The address of the blend token contract - BlendId, - // The address of the blend lp token contract - BlendLPId, // The last timestamp distribution was ran on - LastDistro, + LastDistro(Address), // Stores the list of backstop addresses that have dropped Dropped(Address), - // The last block emissions were forked - LastFork, } /// Bump the instance rent for the contract. Bumps for 10 days due to the 7-day cycle window of this 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); } /********** Backstop **********/ -/// Fetch the current backstop id +/// Fetch the current backstop address /// /// Returns current backstop module contract address pub fn get_backstop(e: &Env) -> Address { e.storage() .instance() - .get(&EmitterDataKey::Backstop) + .get(&Symbol::new(e, BACKSTOP_KEY)) .unwrap_optimized() } -/// Set a new backstop id +/// Set a new backstop address /// /// ### Arguments -/// * `new_backstop_id` - The id for the new backstop -pub fn set_backstop(e: &Env, new_backstop_id: &Address) { +/// * `new_backstop` - The new backstop module contract address +pub fn set_backstop(e: &Env, new_backstop: &Address) { + e.storage() + .instance() + .set::(&Symbol::new(e, BACKSTOP_KEY), new_backstop); +} + +/// Fetch the current backstop token address +/// +/// Returns current backstop module contract address +pub fn get_backstop_token(e: &Env) -> Address { e.storage() .instance() - .set::(&EmitterDataKey::Backstop, new_backstop_id); + .get(&Symbol::new(e, BACKSTOP_TOKEN_KEY)) + .unwrap_optimized() } -/// Check if a backstop has been set +/// Set a new backstop token address /// -/// Returns true if a backstop has been set -pub fn has_backstop(e: &Env) -> bool { - e.storage().instance().has(&EmitterDataKey::Backstop) +/// ### Arguments +/// * `new_backstop_token` - The new backstop token contract address +pub fn set_backstop_token(e: &Env, new_backstop_token: &Address) { + e.storage() + .instance() + .set::(&Symbol::new(e, BACKSTOP_TOKEN_KEY), new_backstop_token); +} + +/// Fetch the current queued backstop swap, or None +pub fn get_queued_swap(e: &Env) -> Option { + if let Some(result) = e.storage().persistent().get(&Symbol::new(e, SWAP_KEY)) { + e.storage().persistent().extend_ttl( + &Symbol::new(e, SWAP_KEY), + LEDGER_THRESHOLD_SHARED, + LEDGER_BUMP_SHARED, + ); + Some(result) + } else { + None + } +} + +/// Set a new swap in the queue +/// +/// ### Arguments +/// * `swap` - The swap to queue +pub fn set_queued_swap(e: &Env, swap: &Swap) { + e.storage() + .persistent() + .set::(&Symbol::new(e, SWAP_KEY), swap); + e.storage().persistent().extend_ttl( + &Symbol::new(e, SWAP_KEY), + LEDGER_THRESHOLD_SHARED, + LEDGER_BUMP_SHARED, + ); +} + +/// Fetch the current queued backstop swap, or None +pub fn del_queued_swap(e: &Env) { + e.storage().persistent().remove(&Symbol::new(e, SWAP_KEY)); } /********** Blend **********/ -/// Fetch the blend token address +/// Fetch the BLND token address /// /// Returns blend token address -pub fn get_blend_id(e: &Env) -> Address { +pub fn get_blnd_token(e: &Env) -> Address { e.storage() .instance() - .get(&EmitterDataKey::BlendId) + .get(&Symbol::new(e, BLND_TOKEN_KEY)) .unwrap_optimized() } -/// Set the blend token address +/// Set the BLND token address /// /// ### Arguments -/// * `blend_id` - The blend token address -pub fn set_blend_id(e: &Env, blend_id: &Address) { +/// * `BLND` - The blend token address +pub fn set_blnd_token(e: &Env, blnd_token: &Address) { e.storage() .instance() - .set::(&EmitterDataKey::BlendId, blend_id); + .set::(&Symbol::new(e, BLND_TOKEN_KEY), blnd_token); +} + +/// Check if the BLND token has been set +/// +/// Returns true if a BLND token has been set +pub fn has_blnd_token(e: &Env) -> bool { + e.storage().instance().has(&Symbol::new(e, BLND_TOKEN_KEY)) } /********** Blend Distributions **********/ @@ -88,31 +140,30 @@ pub fn set_blend_id(e: &Env, blend_id: &Address) { /// Fetch the last timestamp distribution was ran on /// /// Returns the last timestamp distribution was ran on -pub fn get_last_distro_time(e: &Env) -> u64 { - e.storage().persistent().bump( - &EmitterDataKey::LastDistro, - LEDGER_THRESHOLD_SHARED, - LEDGER_BUMP_SHARED, - ); +/// +/// ### Arguments +/// * `backstop` - The backstop module Address +pub fn get_last_distro_time(e: &Env, backstop: &Address) -> u64 { + // don't need to bump while reading since this value is set on every distribution e.storage() .persistent() - .get(&EmitterDataKey::LastDistro) + .get(&EmitterDataKey::LastDistro(backstop.clone())) .unwrap_optimized() } /// Set the last timestamp distribution was ran on /// /// ### Arguments +/// * `backstop` - The backstop module Address /// * `last_distro` - The last timestamp distribution was ran on -pub fn set_last_distro_time(e: &Env, last_distro: &u64) { +pub fn set_last_distro_time(e: &Env, backstop: &Address, last_distro: u64) { + let key = EmitterDataKey::LastDistro(backstop.clone()); e.storage() .persistent() - .set::(&EmitterDataKey::LastDistro, last_distro); - e.storage().persistent().bump( - &EmitterDataKey::LastDistro, - LEDGER_THRESHOLD_SHARED, - LEDGER_BUMP_SHARED, - ); + .set::(&key, &last_distro); + e.storage() + .persistent() + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /// Get whether the emitter has performed the drop distribution or not for the current backstop @@ -141,7 +192,7 @@ pub fn set_drop_status(e: &Env, backstop: &Address) { pub fn get_last_fork(e: &Env) -> u32 { e.storage() .instance() - .get(&EmitterDataKey::LastFork) + .get(&Symbol::new(e, LAST_FORK_KEY)) .unwrap_optimized() } @@ -152,5 +203,5 @@ pub fn get_last_fork(e: &Env) -> u32 { pub fn set_last_fork(e: &Env, block: u32) { e.storage() .instance() - .set::(&EmitterDataKey::LastFork, &block); + .set::(&Symbol::new(e, LAST_FORK_KEY), &block); } diff --git a/emitter/src/testutils.rs b/emitter/src/testutils.rs index 89d755e1..c9410085 100644 --- a/emitter/src/testutils.rs +++ b/emitter/src/testutils.rs @@ -2,18 +2,8 @@ use soroban_sdk::{Address, Env}; -use backstop::{BackstopClient, BackstopContract}; - use crate::EmitterContract; pub(crate) fn create_emitter(e: &Env) -> Address { e.register_contract(None, EmitterContract {}) } - -pub(crate) fn create_backstop(e: &Env) -> (Address, BackstopClient) { - let contract_address = e.register_contract(None, BackstopContract {}); - ( - contract_address.clone(), - BackstopClient::new(e, &contract_address), - ) -} diff --git a/mocks/mock-pool-factory/src/pool_factory.rs b/mocks/mock-pool-factory/src/pool_factory.rs index cdc1d31b..dc7e2a11 100644 --- a/mocks/mock-pool-factory/src/pool_factory.rs +++ b/mocks/mock-pool-factory/src/pool_factory.rs @@ -66,7 +66,7 @@ impl MockPoolFactoryTrait for MockPoolFactory { oracle: Address, backstop_take_rate: u64, ) -> Address { - storage::bump_instance(&e); + storage::extend_instance(&e); let pool_init_meta = storage::get_pool_init_meta(&e); // verify backstop take rate is within [0,1) with 9 decimals diff --git a/mocks/mock-pool-factory/src/storage.rs b/mocks/mock-pool-factory/src/storage.rs index acb9597f..4a22190d 100644 --- a/mocks/mock-pool-factory/src/storage.rs +++ b/mocks/mock-pool-factory/src/storage.rs @@ -21,14 +21,16 @@ pub struct PoolInitMeta { } /// Bump the instance rent for the contract -pub fn bump_instance(e: &Env) { - e.storage().instance().bump(LEDGER_THRESHOLD, LEDGER_BUMP); +pub fn extend_instance(e: &Env) { + e.storage() + .instance() + .extend_ttl(LEDGER_THRESHOLD, LEDGER_BUMP); } /// Fetch the pool initialization metadata pub fn get_pool_init_meta(e: &Env) -> PoolInitMeta { // TODO: Change to instance - https://github.com/stellar/rs-soroban-sdk/issues/1040 - e.storage().persistent().bump( + e.storage().persistent().extend_ttl( &PoolFactoryDataKey::PoolInitMeta, LEDGER_THRESHOLD, LEDGER_BUMP, @@ -69,7 +71,7 @@ pub fn is_deployed(e: &Env, contract_id: &Address) -> bool { { e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD, LEDGER_BUMP); + .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); result } else { false @@ -87,5 +89,5 @@ pub fn set_deployed(e: &Env, contract_id: &Address) { .set::(&key, &true); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD, LEDGER_BUMP); + .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); } diff --git a/pool-factory/src/pool_factory.rs b/pool-factory/src/pool_factory.rs index fcc462cc..f8fbdea8 100644 --- a/pool-factory/src/pool_factory.rs +++ b/pool-factory/src/pool_factory.rs @@ -46,7 +46,7 @@ pub trait PoolFactory { #[contractimpl] impl PoolFactory for PoolFactoryContract { fn initialize(e: Env, pool_init_meta: PoolInitMeta) { - storage::bump_instance(&e); + storage::extend_instance(&e); if storage::has_pool_init_meta(&e) { panic_with_error!(&e, PoolFactoryError::AlreadyInitialized); } @@ -62,7 +62,7 @@ impl PoolFactory for PoolFactoryContract { backstop_take_rate: u64, ) -> Address { admin.require_auth(); - storage::bump_instance(&e); + storage::extend_instance(&e); let pool_init_meta = storage::get_pool_init_meta(&e); // verify backstop take rate is within [0,1) with 9 decimals @@ -92,7 +92,7 @@ impl PoolFactory for PoolFactoryContract { } fn is_pool(e: Env, pool_address: Address) -> bool { - storage::bump_instance(&e); + storage::extend_instance(&e); storage::is_deployed(&e, &pool_address) } } diff --git a/pool-factory/src/storage.rs b/pool-factory/src/storage.rs index e721c9cb..ad726e96 100644 --- a/pool-factory/src/storage.rs +++ b/pool-factory/src/storage.rs @@ -20,8 +20,10 @@ pub struct PoolInitMeta { } /// Bump the instance rent for the contract -pub fn bump_instance(e: &Env) { - e.storage().instance().bump(LEDGER_THRESHOLD, LEDGER_BUMP); +pub fn extend_instance(e: &Env) { + e.storage() + .instance() + .extend_ttl(LEDGER_THRESHOLD, LEDGER_BUMP); } /// Fetch the pool initialization metadata @@ -60,7 +62,7 @@ pub fn is_deployed(e: &Env, contract_id: &Address) -> bool { { e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD, LEDGER_BUMP); + .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); result } else { false @@ -78,5 +80,5 @@ pub fn set_deployed(e: &Env, contract_id: &Address) { .set::(&key, &true); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD, LEDGER_BUMP); + .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); } diff --git a/pool-factory/src/test.rs b/pool-factory/src/test.rs index c79ae70c..a2aa2249 100644 --- a/pool-factory/src/test.rs +++ b/pool-factory/src/test.rs @@ -25,13 +25,13 @@ fn test_pool_factory() { let wasm_hash = e.deployer().upload_contract_wasm(pool::WASM); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); - let oracle = Address::random(&e); - let backstop_id = Address::random(&e); + let oracle = Address::generate(&e); + let backstop_id = Address::generate(&e); let backstop_rate: u64 = 100000; - let blnd_id = Address::random(&e); - let usdc_id = Address::random(&e); + let blnd_id = Address::generate(&e); + let usdc_id = Address::generate(&e); let pool_init_meta = PoolInitMeta { backstop: backstop_id.clone(), @@ -68,7 +68,6 @@ fn test_pool_factory() { let deployed_pool_address_2 = pool_factory_client.deploy(&bombadil, &name2, &salt, &oracle, &backstop_rate); - let zero_address = Address::from_contract_id(&BytesN::from_array(&e, &[0; 32])); e.as_contract(&deployed_pool_address_1, || { assert_eq!( e.storage() @@ -87,7 +86,7 @@ fn test_pool_factory() { assert_eq!( e.storage() .instance() - .get::<_, pool::PoolConfig>(&Symbol::new(&e, "PoolConfig")) + .get::<_, pool::PoolConfig>(&Symbol::new(&e, "Config")) .unwrap(), pool::PoolConfig { oracle: oracle, @@ -110,10 +109,8 @@ fn test_pool_factory() { usdc_id.clone() ); }); - assert_ne!(deployed_pool_address_1, zero_address); - assert_ne!(deployed_pool_address_2, zero_address); assert_ne!(deployed_pool_address_1, deployed_pool_address_2); assert!(pool_factory_client.is_pool(&deployed_pool_address_1)); assert!(pool_factory_client.is_pool(&deployed_pool_address_2)); - assert!(!pool_factory_client.is_pool(&zero_address)); + assert!(!pool_factory_client.is_pool(&Address::generate(&e))); } diff --git a/pool/Cargo.toml b/pool/Cargo.toml index b4ac5bcd..799ddf65 100644 --- a/pool/Cargo.toml +++ b/pool/Cargo.toml @@ -16,7 +16,7 @@ testutils = [ [dependencies] soroban-sdk = { workspace = true } -fixed-point-math = { workspace = true } +soroban-fixed-point-math = { workspace = true } cast = { workspace = true } sep-40-oracle = { workspace = true } sep-41-token = { workspace = true} @@ -28,3 +28,4 @@ backstop = { path = "../backstop", features = ["testutils"] } sep-40-oracle = { workspace = true, features = ["testutils"] } sep-41-token = { workspace = true, features = ["testutils"] } mock-pool-factory = { path = "../mocks/mock-pool-factory", features = ["testutils"] } +emitter = { path = "../emitter", features = ["testutils"] } diff --git a/pool/src/auctions/auction.rs b/pool/src/auctions/auction.rs index f3e07ce5..605cb2fa 100644 --- a/pool/src/auctions/auction.rs +++ b/pool/src/auctions/auction.rs @@ -5,7 +5,7 @@ use crate::{ storage, }; use cast::i128; -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ contracttype, map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Map, }; @@ -275,13 +275,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -409,12 +409,12 @@ mod tests { sequence_number: 50, 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 bombadil = Address::generate(&e); let pool_address = create_pool(&e); let (usdc_id, _) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -423,9 +423,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), - &Address::random(&e), - &Address::random(&e), + &Address::generate(&e), + &Address::generate(&e), + &Address::generate(&e), ); let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); @@ -513,13 +513,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (oracle_address, oracle_client) = testutils::create_mock_oracle(&e); @@ -613,7 +613,7 @@ mod tests { fn test_create_user_liquidation_errors() { let e = Env::default(); let pool_id = create_pool(&e); - let backstop_id = Address::random(&e); + let backstop_id = Address::generate(&e); e.as_contract(&pool_id, || { storage::set_backstop(&e, &backstop_id); @@ -628,7 +628,7 @@ mod tests { e.mock_all_auths(); let pool_id = create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let auction_data = AuctionData { bid: map![&e], @@ -659,7 +659,7 @@ mod tests { e.mock_all_auths(); let pool_id = create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.as_contract(&pool_id, || { delete_liquidation(&e, &samwise); @@ -677,14 +677,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -760,9 +760,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); @@ -784,14 +784,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -867,9 +867,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); @@ -904,14 +904,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -988,9 +988,9 @@ mod tests { sequence_number: 176 + 100, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let mut pool = Pool::load(&e); let mut frodo_state = User::load(&e, &frodo); @@ -1018,9 +1018,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let mut pool = Pool::load(&e); let mut frodo_state = User::load(&e, &frodo); @@ -1047,9 +1047,9 @@ mod tests { sequence_number: 176 + 300, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let mut pool = Pool::load(&e); let mut frodo_state = User::load(&e, &frodo); @@ -1093,14 +1093,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -1175,9 +1175,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); @@ -1212,14 +1212,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -1296,9 +1296,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); @@ -1325,8 +1325,8 @@ mod tests { fn test_scale_auction_100_fill_pct() { // 0 blocks let e = Env::default(); - let underlying_0 = Address::random(&e); - let underlying_1 = Address::random(&e); + let underlying_0 = Address::generate(&e); + let underlying_1 = Address::generate(&e); let base_auction_data = AuctionData { bid: map![&e, (underlying_0.clone(), 100_0000000)], @@ -1341,9 +1341,9 @@ mod tests { sequence_number: 1000, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction) = scale_auction(&e, &base_auction_data, 100); assert_eq!( @@ -1360,9 +1360,9 @@ mod tests { sequence_number: 1100, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction) = scale_auction(&e, &base_auction_data, 100); assert_eq!( @@ -1382,9 +1382,9 @@ mod tests { sequence_number: 1200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction) = scale_auction(&e, &base_auction_data, 100); assert_eq!( @@ -1404,9 +1404,9 @@ mod tests { sequence_number: 1300, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction) = scale_auction(&e, &base_auction_data, 100); assert_eq!( @@ -1426,9 +1426,9 @@ mod tests { sequence_number: 1400, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction) = scale_auction(&e, &base_auction_data, 100); assert_eq!(scaled_auction.bid.len(), 0); @@ -1444,8 +1444,8 @@ mod tests { // @dev: bids always round up, lots always round down // the remaining is exact based on scaled auction let e = Env::default(); - let underlying_0 = Address::random(&e); - let underlying_1 = Address::random(&e); + let underlying_0 = Address::generate(&e); + let underlying_1 = Address::generate(&e); let base_auction_data = AuctionData { bid: map![&e, (underlying_0.clone(), 25_0000005)], @@ -1460,9 +1460,9 @@ mod tests { sequence_number: 1000, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction_option) = scale_auction(&e, &base_auction_data, 50); let remaining_auction = remaining_auction_option.unwrap(); @@ -1487,9 +1487,9 @@ mod tests { sequence_number: 1100, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction_option) = scale_auction(&e, &base_auction_data, 60); @@ -1518,9 +1518,9 @@ mod tests { sequence_number: 1300, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction_option) = scale_auction(&e, &base_auction_data, 60); @@ -1549,9 +1549,9 @@ mod tests { sequence_number: 1400, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 172800, - min_persistent_entry_expiration: 172800, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 172800, + min_persistent_entry_ttl: 172800, + max_entry_ttl: 9999999, }); let (scaled_auction, remaining_auction_option) = scale_auction(&e, &base_auction_data, 50); let remaining_auction = remaining_auction_option.unwrap(); diff --git a/pool/src/auctions/backstop_interest_auction.rs b/pool/src/auctions/backstop_interest_auction.rs index 1b050de4..1245264c 100644 --- a/pool/src/auctions/backstop_interest_auction.rs +++ b/pool/src/auctions/backstop_interest_auction.rs @@ -2,8 +2,8 @@ use crate::{ constants::SCALAR_7, dependencies::BackstopClient, errors::PoolError, pool::Pool, storage, }; use cast::i128; -use fixed_point_math::FixedPoint; use sep_41_token::TokenClient; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{map, panic_with_error, unwrap::UnwrapOptimized, Address, Env}; use super::{AuctionData, AuctionType}; @@ -108,7 +108,7 @@ mod tests { let e = Env::default(); let pool_address = create_pool(&e); - let backstop_address = Address::random(&e); + let backstop_address = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 12345, @@ -116,9 +116,9 @@ mod tests { sequence_number: 100, 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 auction_data = AuctionData { @@ -151,12 +151,12 @@ mod tests { sequence_number: 50, 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 bombadil = Address::generate(&e); let pool_address = create_pool(&e); let (usdc_id, _) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -165,9 +165,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), + &Address::generate(&e), &usdc_id, - &Address::random(&e), + &Address::generate(&e), ); let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); @@ -262,12 +262,12 @@ mod tests { sequence_number: 50, 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 bombadil = Address::generate(&e); let pool_address = create_pool(&e); let (usdc_id, _) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -276,9 +276,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), + &Address::generate(&e), &usdc_id, - &Address::random(&e), + &Address::generate(&e), ); let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); @@ -373,12 +373,12 @@ mod tests { sequence_number: 150, 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 bombadil = Address::generate(&e); let pool_address = create_pool(&e); let (usdc_id, _) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -387,9 +387,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), + &Address::generate(&e), &usdc_id, - &Address::random(&e), + &Address::generate(&e), ); let (oracle_id, oracle_client) = testutils::create_mock_oracle(&e); @@ -486,13 +486,13 @@ mod tests { sequence_number: 301, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); @@ -502,9 +502,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), + &Address::generate(&e), &usdc_id, - &Address::random(&e), + &Address::generate(&e), ); let (underlying_0, underlying_0_client) = testutils::create_token_contract(&e, &bombadil); @@ -542,7 +542,7 @@ mod tests { underlying_1_client.mint(&pool_address, &1_000_0000000); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; diff --git a/pool/src/auctions/bad_debt_auction.rs b/pool/src/auctions/bad_debt_auction.rs index 62c7e29f..af541f9f 100644 --- a/pool/src/auctions/bad_debt_auction.rs +++ b/pool/src/auctions/bad_debt_auction.rs @@ -6,7 +6,7 @@ use crate::{ storage, }; use cast::i128; -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{map, panic_with_error, unwrap::UnwrapOptimized, Address, Env}; use super::{AuctionData, AuctionType}; @@ -131,8 +131,8 @@ mod tests { e.budget().reset_unlimited(); // setup exhausts budget let pool_address = create_pool(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); let (usdc, usdc_client) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -166,9 +166,9 @@ mod tests { sequence_number: 100, 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 auction_data = AuctionData { @@ -200,13 +200,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -333,13 +333,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -467,13 +467,13 @@ mod tests { sequence_number: 150, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -601,13 +601,13 @@ mod tests { sequence_number: 51, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); @@ -676,7 +676,7 @@ mod tests { &reserve_data_2, ); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -745,13 +745,13 @@ mod tests { sequence_number: 51, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -819,7 +819,7 @@ mod tests { &reserve_data_2, ); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -895,13 +895,13 @@ mod tests { sequence_number: 51, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (blnd, blnd_client) = testutils::create_blnd_token(&e, &pool_address, &bombadil); @@ -969,7 +969,7 @@ mod tests { &reserve_data_2, ); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; diff --git a/pool/src/auctions/user_liquidation_auction.rs b/pool/src/auctions/user_liquidation_auction.rs index 381366b7..e3c04944 100644 --- a/pool/src/auctions/user_liquidation_auction.rs +++ b/pool/src/auctions/user_liquidation_auction.rs @@ -1,5 +1,5 @@ use cast::i128; -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::unwrap::UnwrapOptimized; use soroban_sdk::{map, panic_with_error, Address, Env}; @@ -157,7 +157,7 @@ mod tests { let pool_address = create_pool(&e); let (oracle, _) = testutils::create_mock_oracle(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 12345, @@ -165,9 +165,9 @@ mod tests { sequence_number: 100, 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 liq_pct = 50; @@ -205,13 +205,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (oracle_address, oracle_client) = testutils::create_mock_oracle(&e); @@ -317,13 +317,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); @@ -424,13 +424,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); @@ -532,13 +532,13 @@ mod tests { sequence_number: 50, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); @@ -639,14 +639,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 17280, - min_persistent_entry_expiration: 17280, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 17280, + min_persistent_entry_ttl: 17280, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -748,9 +748,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 17280, - min_persistent_entry_expiration: 17280, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 17280, + min_persistent_entry_ttl: 17280, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); @@ -814,14 +814,14 @@ mod tests { sequence_number: 175, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 17280, - min_persistent_entry_expiration: 17280, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 17280, + min_persistent_entry_ttl: 17280, + max_entry_ttl: 9999999, }); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -923,9 +923,9 @@ mod tests { sequence_number: 176 + 200, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 17280, - min_persistent_entry_expiration: 17280, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 17280, + min_persistent_entry_ttl: 17280, + max_entry_ttl: 9999999, }); e.budget().reset_unlimited(); let mut pool = Pool::load(&e); diff --git a/pool/src/contract.rs b/pool/src/contract.rs index d9d05a94..f6924712 100644 --- a/pool/src/contract.rs +++ b/pool/src/contract.rs @@ -145,12 +145,11 @@ pub trait Pool { /********* Emission Functions **********/ - /// Update emissions for reserves for the next emission cycle + /// Consume emissions from the backstop and distribute to the reserves based + /// on the reserve emission configuration. /// - /// Needs to be performed each emission cycle, as determined by the expiration - /// - /// Returns the expiration timestamp - fn update_emissions(e: Env) -> u64; + /// Returns amount of new tokens emitted + fn gulp_emissions(e: Env) -> i128; /// (Admin only) Set the emission configuration for the pool /// @@ -219,7 +218,7 @@ impl Pool for PoolContract { blnd_id: Address, usdc_id: Address, ) { - storage::bump_instance(&e); + storage::extend_instance(&e); pool::execute_initialize( &e, @@ -234,7 +233,7 @@ impl Pool for PoolContract { } fn set_admin(e: Env, new_admin: Address) { - storage::bump_instance(&e); + storage::extend_instance(&e); let admin = storage::get_admin(&e); admin.require_auth(); @@ -245,7 +244,7 @@ impl Pool for PoolContract { } fn update_pool(e: Env, backstop_take_rate: u64) { - storage::bump_instance(&e); + storage::extend_instance(&e); let admin = storage::get_admin(&e); admin.require_auth(); @@ -256,7 +255,7 @@ impl Pool for PoolContract { } fn init_reserve(e: Env, asset: Address, config: ReserveConfig) -> u32 { - storage::bump_instance(&e); + storage::extend_instance(&e); let admin = storage::get_admin(&e); admin.require_auth(); @@ -268,7 +267,7 @@ impl Pool for PoolContract { } fn update_reserve(e: Env, asset: Address, config: ReserveConfig) { - storage::bump_instance(&e); + storage::extend_instance(&e); let admin = storage::get_admin(&e); admin.require_auth(); @@ -289,7 +288,7 @@ impl Pool for PoolContract { to: Address, requests: Vec, ) -> Positions { - storage::bump_instance(&e); + storage::extend_instance(&e); spender.require_auth(); if from != spender { from.require_auth(); @@ -318,9 +317,9 @@ impl Pool for PoolContract { /********* Emission Functions **********/ - fn update_emissions(e: Env) -> u64 { - storage::bump_instance(&e); - let next_expiration = pool::update_pool_emissions(&e); + fn gulp_emissions(e: Env) -> i128 { + storage::extend_instance(&e); + let next_expiration = emissions::gulp_emissions(&e); e.events() .publish((Symbol::new(&e, "update_emissions"),), next_expiration); @@ -335,7 +334,7 @@ impl Pool for PoolContract { } fn claim(e: Env, from: Address, reserve_token_ids: Vec, to: Address) -> i128 { - storage::bump_instance(&e); + storage::extend_instance(&e); from.require_auth(); let amount_claimed = emissions::execute_claim(&e, &from, &reserve_token_ids, &to); @@ -365,7 +364,7 @@ impl Pool for PoolContract { } fn new_auction(e: Env, auction_type: u32) -> AuctionData { - storage::bump_instance(&e); + storage::extend_instance(&e); let auction_data = auctions::create(&e, auction_type); e.events().publish( diff --git a/pool/src/emissions/distributor.rs b/pool/src/emissions/distributor.rs index 83dd1628..b7478e7d 100644 --- a/pool/src/emissions/distributor.rs +++ b/pool/src/emissions/distributor.rs @@ -1,12 +1,13 @@ use cast::i128; -use fixed_point_math::FixedPoint; use sep_41_token::TokenClient; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{panic_with_error, unwrap::UnwrapOptimized, Address, Env, Vec}; use crate::{ errors::PoolError, pool::User, storage::{self, ReserveEmissionsData, UserEmissionData}, + ReserveEmissionsConfig, }; /// Performs a claim against the given "reserve_token_ids" for "from" @@ -117,28 +118,43 @@ pub fn update_emission_data( supply: i128, supply_scalar: i128, ) -> Option { - let token_emission_config = match storage::get_res_emis_config(e, &res_token_id) { - Some(res) => res, + match storage::get_res_emis_config(e, &res_token_id) { + Some(emis_config) => Some(update_emission_data_with_config( + e, + res_token_id, + supply, + supply_scalar, + &emis_config, + )), None => return None, // no emission exist, no update is required - }; + } +} + +pub(super) fn update_emission_data_with_config( + e: &Env, + res_token_id: u32, + supply: i128, + supply_scalar: i128, + emis_config: &ReserveEmissionsConfig, +) -> ReserveEmissionsData { let token_emission_data = storage::get_res_emis_data(e, &res_token_id).unwrap_optimized(); // exists if config is written to - if token_emission_data.last_time >= token_emission_config.expiration + if token_emission_data.last_time >= emis_config.expiration || e.ledger().timestamp() == token_emission_data.last_time - || token_emission_config.eps == 0 + || emis_config.eps == 0 || supply == 0 { - return Some(token_emission_data); + return token_emission_data; } - let ledger_timestamp = if e.ledger().timestamp() > token_emission_config.expiration { - token_emission_config.expiration + let ledger_timestamp = if e.ledger().timestamp() > emis_config.expiration { + emis_config.expiration } else { e.ledger().timestamp() }; let additional_idx = (i128(ledger_timestamp - token_emission_data.last_time) - * i128(token_emission_config.eps)) + * i128(emis_config.eps)) .fixed_div_floor(supply, supply_scalar) .unwrap_optimized(); let new_data = ReserveEmissionsData { @@ -146,7 +162,7 @@ pub fn update_emission_data( last_time: ledger_timestamp, }; storage::set_res_emis_data(e, &res_token_id, &new_data); - Some(new_data) + new_data } fn update_user_emissions( @@ -223,7 +239,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1501000000, // 10^6 seconds have passed @@ -231,9 +247,9 @@ mod tests { sequence_number: 123, 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 supply: i128 = 50_0000000; @@ -287,7 +303,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1501000000, // 10^6 seconds have passed @@ -295,9 +311,9 @@ mod tests { sequence_number: 123, 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 supply: i128 = 100_0000000; @@ -339,9 +355,9 @@ mod tests { sequence_number: 123, 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 supply = 50_0000000; @@ -378,9 +394,9 @@ mod tests { sequence_number: 123, 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 supply = 50_0000000; @@ -429,9 +445,9 @@ mod tests { sequence_number: 123, 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 supply = 50_0000000; @@ -480,9 +496,9 @@ mod tests { sequence_number: 123, 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 supply = 50_0000000; @@ -531,9 +547,9 @@ mod tests { sequence_number: 123, 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 supply = 0; @@ -582,9 +598,9 @@ mod tests { sequence_number: 123, 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 supply = 100_0000000; @@ -630,9 +646,9 @@ mod tests { sequence_number: 123, 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 supply = 100_0001111; @@ -673,7 +689,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -681,9 +697,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -719,7 +735,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -727,9 +743,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -765,7 +781,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -773,9 +789,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -818,7 +834,7 @@ mod tests { let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -826,9 +842,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -870,7 +886,7 @@ mod tests { e.mock_all_auths(); let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -878,9 +894,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -923,7 +939,7 @@ mod tests { let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -931,9 +947,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -977,7 +993,7 @@ mod tests { let pool = testutils::create_pool(&e); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1500000000, @@ -985,9 +1001,9 @@ mod tests { sequence_number: 123, 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 supply_scalar = 1_0000000; @@ -1026,9 +1042,9 @@ mod tests { e.budget().reset_unlimited(); let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let merry = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let merry = Address::generate(&e); let (_, blnd_token_client) = testutils::create_blnd_token(&e, &pool, &bombadil); let (backstop, _) = testutils::create_backstop(&e); @@ -1044,9 +1060,9 @@ mod tests { sequence_number: 123, 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 (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); @@ -1152,9 +1168,9 @@ mod tests { e.budget().reset_unlimited(); let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let merry = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let merry = Address::generate(&e); let (backstop, _) = testutils::create_backstop(&e); let (_, blnd_token_client) = testutils::create_blnd_token(&e, &pool, &bombadil); @@ -1171,9 +1187,9 @@ mod tests { sequence_number: 123, 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 (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); diff --git a/pool/src/emissions/manager.rs b/pool/src/emissions/manager.rs index 26f398ff..0fe5efaf 100644 --- a/pool/src/emissions/manager.rs +++ b/pool/src/emissions/manager.rs @@ -1,8 +1,11 @@ use crate::{ + constants::SCALAR_7, + dependencies::BackstopClient, errors::PoolError, storage::{self, ReserveEmissionsConfig, ReserveEmissionsData}, }; -use fixed_point_math::FixedPoint; +use cast::{i128, u64}; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ contracttype, map, panic_with_error, unwrap::UnwrapOptimized, Address, Env, Map, Symbol, Vec, }; @@ -50,36 +53,45 @@ pub fn set_pool_emissions(e: &Env, res_emission_metadata: Vec u64 { - let cur_exp = storage::get_pool_emissions_expiration(e); - if next_exp <= cur_exp { - panic_with_error!(e, PoolError::BadRequest); - } +pub fn gulp_emissions(e: &Env) -> i128 { + let backstop = storage::get_backstop(e); + let new_emissions = + BackstopClient::new(e, &backstop).gulp_pool_emissions(&e.current_contract_address()); + do_gulp_emissions(e, new_emissions); + new_emissions +} +fn do_gulp_emissions(e: &Env, new_emissions: i128) { + // ensure enough tokens are being emitted to avoid rounding issues + if new_emissions < SCALAR_7 { + panic_with_error!(e, PoolError::BadRequest) + } let pool_emissions = storage::get_pool_emissions(e); let reserve_list = storage::get_res_list(e); for (res_token_id, res_eps_share) in pool_emissions.iter() { let reserve_index = res_token_id / 2; let res_asset_address = reserve_list.get_unchecked(reserve_index); - // update emissions data first to use the previous config until the current ledger timestamp - update_reserve_emission_data(e, &res_asset_address, res_token_id); - update_reserve_emission_config(e, res_token_id, next_exp, pool_eps, res_eps_share); + let new_reserve_emissions = i128(res_eps_share) + .fixed_mul_floor(new_emissions, SCALAR_7) + .unwrap_optimized(); + update_reserve_emission_config(e, &res_asset_address, res_token_id, new_reserve_emissions); } - - storage::set_pool_emissions_expiration(e, &next_exp); - next_exp } -fn update_reserve_emission_data(e: &Env, asset: &Address, res_token_id: u32) { - if storage::has_res_emis_data(e, &res_token_id) { +fn update_reserve_emission_config( + e: &Env, + asset: &Address, + res_token_id: u32, + new_reserve_emissions: i128, +) { + let mut tokens_left_to_emit = new_reserve_emissions; + if let Some(emis_config) = storage::get_res_emis_config(e, &res_token_id) { // data exists - update it with old config let reserve_config = storage::get_res_config(e, asset); let reserve_data = storage::get_res_data(e, asset); @@ -88,20 +100,26 @@ fn update_reserve_emission_data(e: &Env, asset: &Address, res_token_id: u32) { 1 => reserve_data.b_supply, _ => panic_with_error!(e, PoolError::BadRequest), }; - let mut emission_data = distributor::update_emission_data( + let mut emission_data = distributor::update_emission_data_with_config( e, res_token_id, supply, 10i128.pow(reserve_config.decimals), - ) - .unwrap(); // will always return a result + &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_res_emis_data(e, &res_token_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 { - // no data exists yet - first time this reserve token will get emission + // no config or data exists yet - first time this reserve token will get emission storage::set_res_emis_data( e, &res_token_id, @@ -111,27 +129,14 @@ fn update_reserve_emission_data(e: &Env, asset: &Address, res_token_id: u32) { }, ); } -} - -fn update_reserve_emission_config( - e: &Env, - res_token_id: u32, - expiration: u64, - pool_eps: u64, - eps_share: u64, -) { - let new_res_eps = eps_share - .fixed_mul_floor(pool_eps, 1_0000000) - .unwrap_optimized(); - let new_reserve_emis_config = ReserveEmissionsConfig { - expiration, - eps: new_res_eps, - }; - + let expiration = e.ledger().timestamp() + 7 * 24 * 60 * 60; + let eps = u64(tokens_left_to_emit / (7 * 24 * 60 * 60)).unwrap_optimized(); + let new_reserve_emis_config = ReserveEmissionsConfig { expiration, eps }; storage::set_res_emis_config(e, &res_token_id, &new_reserve_emis_config); + e.events().publish( - (Symbol::new(e, "e_config"),), - (res_token_id, new_res_eps, expiration), + (Symbol::new(e, "reserve_emission_update"),), + (res_token_id, eps, expiration), ) } @@ -146,10 +151,10 @@ mod tests { vec, Address, }; - /********** update emissions cycle ********/ + /********** gulp_emissions ********/ #[test] - fn test_update_emissions_cycle_no_emitted_reserves_does_nothing() { + fn test_gulp_emissions_no_pool_emissions_does_nothing() { let e = Env::default(); e.mock_all_auths(); e.ledger().set(LedgerInfo { @@ -158,16 +163,15 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); - let next_exp = 1500604800; - let pool_eps = 0_5000000; + let new_emissions: i128 = 302_400_0000000; let pool_emissions: Map = map![&e]; let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -179,9 +183,7 @@ mod tests { e.as_contract(&pool, || { storage::set_pool_emissions(&e, &pool_emissions); - update_emissions_cycle(&e, next_exp, pool_eps); - - assert_eq!(storage::get_pool_emissions_expiration(&e), next_exp); + do_gulp_emissions(&e, new_emissions); assert!(storage::get_res_emis_config(&e, &0).is_none()); assert!(storage::get_res_emis_config(&e, &1).is_none()); @@ -191,7 +193,7 @@ mod tests { } #[test] - fn test_update_emissions_cycle_sets_reserve_emission_when_emitting_both() { + fn test_gulp_emissions() { let e = Env::default(); e.mock_all_auths(); e.ledger().set(LedgerInfo { @@ -200,19 +202,19 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); - let next_exp = 1500604800; - let pool_eps = 0_5000000; + let new_emissions: i128 = 302_400_0000000; let pool_emissions: Map = map![ &e, - (2, 0_7500000), // reserve_1 liability + (0, 0_2000000), // reserve_0 liability + (2, 0_5500000), // reserve_1 liability (3, 0_2500000) // reserve_1 supply ]; @@ -225,215 +227,69 @@ mod tests { let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); - e.as_contract(&pool, || { - storage::set_pool_emissions(&e, &pool_emissions); - - update_emissions_cycle(&e, next_exp, pool_eps); - - assert_eq!(storage::get_pool_emissions_expiration(&e), next_exp); - - assert!(storage::get_res_emis_config(&e, &0).is_none()); - assert!(storage::get_res_emis_config(&e, &1).is_none()); - assert!(storage::get_res_emis_config(&e, &4).is_none()); - assert!(storage::get_res_emis_config(&e, &5).is_none()); - - let r_1_l_config = storage::get_res_emis_config(&e, &2).unwrap_optimized(); - let r_1_s_config = storage::get_res_emis_config(&e, &3).unwrap_optimized(); - assert_eq!(r_1_l_config.expiration, next_exp); - assert_eq!(r_1_l_config.eps, 0_3750000); - assert_eq!(r_1_s_config.expiration, next_exp); - assert_eq!(r_1_s_config.eps, 0_1250000); - - // verify empty data was created for both - let r_1_l_data = storage::get_res_emis_data(&e, &2).unwrap_optimized(); - let r_1_s_data = storage::get_res_emis_data(&e, &3).unwrap_optimized(); - assert_eq!(r_1_l_data.index, 0); - assert_eq!(r_1_l_data.last_time, 1500000000); - assert_eq!(r_1_s_data.index, 0); - assert_eq!(r_1_s_data.last_time, 1500000000); - }); - } - - #[test] - fn test_update_emissions_cycle_sets_reserve_emission_config_and_data() { - let e = Env::default(); - e.mock_all_auths(); - - let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); - - e.ledger().set(LedgerInfo { - timestamp: 1500000000, - protocol_version: 20, - sequence_number: 20100, - network_id: Default::default(), - base_reserve: 10, - min_temp_entry_expiration: 10, - min_persistent_entry_expiration: 10, - max_entry_expiration: 2000000, - }); - - let next_exp = 1500604800; - let pool_eps = 0_5000000; - let pool_emissions: Map = map![ - &e, - (0, 0_2500000), // reserve_0 liabilities - (5, 0_7500000) // reserve_1 supply - ]; - - let old_r_l_0_config = ReserveEmissionsConfig { - eps: 0_2000000, - expiration: 1500000100, - }; - let old_r_l_0_data = ReserveEmissionsData { - index: 100, - last_time: 1499980000, - }; - let old_r_s_2_config = ReserveEmissionsConfig { - eps: 0_3000000, - expiration: 1500000100, + // setup reserve_0 liability to have emissions remaining + let old_r_0_l_config = ReserveEmissionsConfig { + eps: 0_1500000, + expiration: 1500000200, }; - let old_r_s_2_data = ReserveEmissionsData { - index: 500, + let old_r_0_l_data = ReserveEmissionsData { + index: 99999, last_time: 1499980000, }; - let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.last_time = 1499900000; - let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); - testutils::create_reserve(&e, &pool, &underlying_0, &reserve_config, &reserve_data); - let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); - testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); - let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); - reserve_data.b_supply = 100_0000000; - reserve_data.d_supply = 50_0000000; - testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); + // setup reserve_1 liability to have no emissions + // steup reserve_1 supply to have emissions expired + let old_r_1_s_config = ReserveEmissionsConfig { + eps: 0_3500000, + expiration: 1499990000, + }; + let old_r_1_s_data = ReserveEmissionsData { + index: 11111, + last_time: 1499990000, + }; e.as_contract(&pool, || { storage::set_pool_emissions(&e, &pool_emissions); - storage::set_res_emis_config(&e, &0, &old_r_l_0_config); - storage::set_res_emis_data(&e, &0, &old_r_l_0_data); - storage::set_res_emis_config(&e, &5, &old_r_s_2_config); - storage::set_res_emis_data(&e, &5, &old_r_s_2_data); + storage::set_res_emis_config(&e, &0, &old_r_0_l_config); + storage::set_res_emis_data(&e, &0, &old_r_0_l_data); + storage::set_res_emis_config(&e, &3, &old_r_1_s_config); + storage::set_res_emis_data(&e, &3, &old_r_1_s_data); - let result = update_emissions_cycle(&e, next_exp, pool_eps); - - assert_eq!(storage::get_pool_emissions_expiration(&e), next_exp); - assert_eq!(result, next_exp); + do_gulp_emissions(&e, new_emissions); assert!(storage::get_res_emis_config(&e, &1).is_none()); - assert!(storage::get_res_emis_config(&e, &2).is_none()); - assert!(storage::get_res_emis_config(&e, &3).is_none()); assert!(storage::get_res_emis_config(&e, &4).is_none()); + assert!(storage::get_res_emis_config(&e, &5).is_none()); + // verify reserve_0 liability leftover emissions were carried over let r_0_l_config = storage::get_res_emis_config(&e, &0).unwrap_optimized(); - let r_2_s_config = storage::get_res_emis_config(&e, &5).unwrap_optimized(); - assert_eq!(r_0_l_config.expiration, next_exp); - assert_eq!(r_0_l_config.eps, 0_1250000); - assert_eq!(r_2_s_config.expiration, next_exp); - assert_eq!(r_2_s_config.eps, 0_3750000); - let r_0_l_data = storage::get_res_emis_data(&e, &0).unwrap_optimized(); - let r_2_s_data = storage::get_res_emis_data(&e, &5).unwrap_optimized(); - assert_eq!(r_0_l_data.index, 533333433); + assert_eq!(r_0_l_config.expiration, 1500000000 + 7 * 24 * 60 * 60); + assert_eq!(r_0_l_config.eps, 0_1000496); + assert_eq!(r_0_l_data.index, 99999 + 40 * SCALAR_7); assert_eq!(r_0_l_data.last_time, 1500000000); - assert_eq!(r_2_s_data.index, 600000500); - assert_eq!(r_2_s_data.last_time, 1500000000); - }); - } - - #[test] - fn test_update_emissions_cycle_all_data_set_to_ledger_timestamp() { - let e = Env::default(); - e.mock_all_auths(); - - let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); - - e.ledger().set(LedgerInfo { - timestamp: 1500100000, - protocol_version: 20, - sequence_number: 20100, - network_id: Default::default(), - base_reserve: 10, - min_temp_entry_expiration: 10, - min_persistent_entry_expiration: 10, - max_entry_expiration: 2000000, - }); - - let next_exp = 1500704800; - let pool_eps = 0_5000000; - let pool_emissions: Map = map![ - &e, - (0, 0_2500000), // reserve_0 liabilities - (5, 0_7500000) // reserve_1 supply - ]; - - let old_r_l_0_config = ReserveEmissionsConfig { - eps: 0_2000000, - expiration: 1500000100, - }; - let old_r_l_0_data = ReserveEmissionsData { - index: 100, - last_time: 1500000200, - }; - let old_r_s_2_config = ReserveEmissionsConfig { - eps: 0_3000000, - expiration: 1500000100, - }; - let old_r_s_2_data = ReserveEmissionsData { - index: 500, - last_time: 1500000100, - }; - - let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); - reserve_data.last_time = 1499900000; - let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); - testutils::create_reserve(&e, &pool, &underlying_0, &reserve_config, &reserve_data); - let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); - testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); - let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); - reserve_data.b_supply = 100_0000000; - reserve_data.d_supply = 50_0000000; - testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); - - e.as_contract(&pool, || { - storage::set_pool_emissions(&e, &pool_emissions); - storage::set_res_emis_config(&e, &0, &old_r_l_0_config); - storage::set_res_emis_data(&e, &0, &old_r_l_0_data); - storage::set_res_emis_config(&e, &5, &old_r_s_2_config); - storage::set_res_emis_data(&e, &5, &old_r_s_2_data); - - let result = update_emissions_cycle(&e, next_exp, pool_eps); - assert_eq!(storage::get_pool_emissions_expiration(&e), next_exp); - assert_eq!(result, next_exp); - - assert!(storage::get_res_emis_config(&e, &1).is_none()); - assert!(storage::get_res_emis_config(&e, &2).is_none()); - assert!(storage::get_res_emis_config(&e, &3).is_none()); - assert!(storage::get_res_emis_config(&e, &4).is_none()); - - let r_0_l_config = storage::get_res_emis_config(&e, &0).unwrap_optimized(); - let r_2_s_config = storage::get_res_emis_config(&e, &5).unwrap_optimized(); - assert_eq!(r_0_l_config.expiration, next_exp); - assert_eq!(r_0_l_config.eps, 0_1250000); - assert_eq!(r_2_s_config.expiration, next_exp); - assert_eq!(r_2_s_config.eps, 0_3750000); + // verify reserve_1 liability initialized emissions + let r_1_l_config = storage::get_res_emis_config(&e, &2).unwrap_optimized(); + let r_1_l_data = storage::get_res_emis_data(&e, &2).unwrap_optimized(); + assert_eq!(r_1_l_config.expiration, 1500000000 + 7 * 24 * 60 * 60); + assert_eq!(r_1_l_config.eps, 0_2750000); + assert_eq!(r_1_l_data.index, 0); + assert_eq!(r_1_l_data.last_time, 1500000000); - // should not accrue any value to index due to already passing the last expiration - let r_0_l_data = storage::get_res_emis_data(&e, &0).unwrap_optimized(); - let r_2_s_data = storage::get_res_emis_data(&e, &5).unwrap_optimized(); - assert_eq!(r_0_l_data.index, 100); - assert_eq!(r_0_l_data.last_time, 1500100000); - assert_eq!(r_2_s_data.index, 500); - assert_eq!(r_2_s_data.last_time, 1500100000); + // verify reserve_1 supply updated reserve data to the correct timestamp + let r_1_s_config = storage::get_res_emis_config(&e, &3).unwrap_optimized(); + let r_1_s_data = storage::get_res_emis_data(&e, &3).unwrap_optimized(); + assert_eq!(r_1_s_config.expiration, 1500000000 + 7 * 24 * 60 * 60); + assert_eq!(r_1_s_config.eps, 0_1250000); + assert_eq!(r_1_s_data.index, 11111); + assert_eq!(r_1_s_data.last_time, 1500000000); }); } #[test] #[should_panic(expected = "Error(Contract, #2)")] - fn test_update_emissions_cycle_panics_if_already_updated() { + fn test_gulp_emissions_too_small() { let e = Env::default(); e.mock_all_auths(); e.ledger().set(LedgerInfo { @@ -442,17 +298,21 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); - let next_exp = 1500604800; - let pool_eps = 0_5000000; - let pool_emissions: Map = map![&e, (2, 0_7500000), (3, 0_2500000)]; + let new_emissions: i128 = 1000000; + let pool_emissions: Map = map![ + &e, + (0, 0_2000000), // reserve_0 liability + (2, 0_5500000), // reserve_1 liability + (3, 0_2500000) // reserve_1 supply + ]; let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); reserve_data.last_time = 1499900000; @@ -461,15 +321,37 @@ mod tests { let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let (underlying_2, _) = testutils::create_token_contract(&e, &bombadil); - reserve_data.b_supply = 100_0000000; - reserve_data.d_supply = 50_0000000; testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); + // setup reserve_0 liability to have emissions remaining + let old_r_0_l_config = ReserveEmissionsConfig { + eps: 0_1500000, + expiration: 1500000200, + }; + let old_r_0_l_data = ReserveEmissionsData { + index: 99999, + last_time: 1499980000, + }; + + // setup reserve_1 liability to have no emissions + + // steup reserve_1 supply to have emissions expired + let old_r_1_s_config = ReserveEmissionsConfig { + eps: 0_3500000, + expiration: 1499990000, + }; + let old_r_1_s_data = ReserveEmissionsData { + index: 11111, + last_time: 1499990000, + }; e.as_contract(&pool, || { - storage::set_pool_emissions_expiration(&e, &1500604800); storage::set_pool_emissions(&e, &pool_emissions); + storage::set_res_emis_config(&e, &0, &old_r_0_l_config); + storage::set_res_emis_data(&e, &0, &old_r_0_l_data); + storage::set_res_emis_config(&e, &3, &old_r_1_s_config); + storage::set_res_emis_data(&e, &3, &old_r_1_s_data); - update_emissions_cycle(&e, next_exp, pool_eps); + do_gulp_emissions(&e, new_emissions); }); } @@ -486,13 +368,13 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); @@ -541,13 +423,13 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); @@ -575,7 +457,6 @@ mod tests { ]; e.as_contract(&pool, || { - storage::set_pool_emissions_expiration(&e, &1000); storage::set_pool_emissions(&e, &pool_emissions); set_pool_emissions(&e, res_emission_metadata); @@ -593,13 +474,13 @@ mod tests { sequence_number: 20100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); diff --git a/pool/src/emissions/mod.rs b/pool/src/emissions/mod.rs index 2bf1e14c..2f937449 100644 --- a/pool/src/emissions/mod.rs +++ b/pool/src/emissions/mod.rs @@ -1,5 +1,5 @@ mod manager; -pub use manager::{set_pool_emissions, update_emissions_cycle, ReserveEmissionMetadata}; +pub use manager::{gulp_emissions, set_pool_emissions, ReserveEmissionMetadata}; mod distributor; pub use distributor::{execute_claim, update_emissions}; diff --git a/pool/src/pool/actions.rs b/pool/src/pool/actions.rs index 9b00bc08..deeec137 100644 --- a/pool/src/pool/actions.rs +++ b/pool/src/pool/actions.rs @@ -310,8 +310,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -324,12 +324,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -378,8 +378,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -392,12 +392,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -451,8 +451,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -465,12 +465,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -521,8 +521,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -535,12 +535,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -592,8 +592,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -606,12 +606,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -664,8 +664,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -678,12 +678,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -734,8 +734,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -747,12 +747,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -797,8 +797,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -811,12 +811,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -870,8 +870,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -884,12 +884,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -942,8 +942,8 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); @@ -963,12 +963,12 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_200_000_000, status: 0, }; @@ -1050,14 +1050,14 @@ mod tests { sequence_number: 176 + 200, 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 samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -1185,14 +1185,14 @@ mod tests { sequence_number: 51 + 200, 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 samwise = Address::random(&e); - let frodo = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); let pool_address = create_pool(&e); @@ -1208,8 +1208,8 @@ mod tests { &pool_address, &backstop_address, &backstop_token_id, - &Address::random(&e), - &Address::random(&e), + &Address::generate(&e), + &Address::generate(&e), ); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); let (mut reserve_config_0, mut reserve_data_0) = testutils::default_reserve_meta(); @@ -1307,13 +1307,13 @@ mod tests { sequence_number: 51 + 200, 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 samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let pool_address = create_pool(&e); let (usdc_id, usdc_client) = testutils::create_usdc_token(&e, &pool_address, &bombadil); @@ -1322,9 +1322,9 @@ mod tests { &e, &pool_address, &backstop_address, - &Address::random(&e), + &Address::generate(&e), &usdc_id, - &Address::random(&e), + &Address::generate(&e), ); let (underlying_0, underlying_0_client) = testutils::create_token_contract(&e, &bombadil); @@ -1370,7 +1370,7 @@ mod tests { underlying_2_client.mint(&pool_address, &1_000_0000000); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -1441,19 +1441,19 @@ mod tests { sequence_number: 51 + 200, 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 samwise = Address::random(&e); - let underlying_0 = Address::random(&e); - let underlying_1 = Address::random(&e); + let samwise = Address::generate(&e); + let underlying_0 = Address::generate(&e); + let underlying_1 = Address::generate(&e); let pool_address = create_pool(&e); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -1483,7 +1483,7 @@ mod tests { &e, Request { request_type: 9, - address: Address::random(&e), + address: Address::generate(&e), amount: 0, }, ]; diff --git a/pool/src/pool/bad_debt.rs b/pool/src/pool/bad_debt.rs index aabd6eb0..0e1279a7 100644 --- a/pool/src/pool/bad_debt.rs +++ b/pool/src/pool/bad_debt.rs @@ -92,16 +92,16 @@ mod tests { sequence_number: 123, 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 pool = testutils::create_pool(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); - let samwise = Address::random(&e); - let bombadil = Address::random(&e); + let samwise = Address::generate(&e); + let bombadil = Address::generate(&e); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -113,7 +113,7 @@ mod tests { testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -158,16 +158,16 @@ mod tests { sequence_number: 123, 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 pool = testutils::create_pool(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); - let samwise = Address::random(&e); - let bombadil = Address::random(&e); + let samwise = Address::generate(&e); + let bombadil = Address::generate(&e); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -179,7 +179,7 @@ mod tests { testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -210,16 +210,16 @@ mod tests { sequence_number: 123, 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 pool = testutils::create_pool(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); - let samwise = Address::random(&e); - let bombadil = Address::random(&e); + let samwise = Address::generate(&e); + let bombadil = Address::generate(&e); let (underlying_1, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -231,7 +231,7 @@ mod tests { testutils::create_reserve(&e, &pool, &underlying_2, &reserve_config, &reserve_data); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -258,16 +258,16 @@ mod tests { sequence_number: 123, 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 pool = testutils::create_pool(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); - let samwise = Address::random(&e); - let bombadil = Address::random(&e); + let samwise = Address::generate(&e); + let bombadil = Address::generate(&e); let (underlying_0, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -279,7 +279,7 @@ mod tests { testutils::create_reserve(&e, &pool, &underlying_1, &reserve_config, &reserve_data); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -309,14 +309,14 @@ mod tests { sequence_number: 123, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let backstop = Address::random(&e); + let backstop = Address::generate(&e); let (_, blnd_client) = testutils::create_blnd_token(&e, &pool, &bombadil); @@ -334,7 +334,7 @@ mod tests { blnd_client.mint(&backstop, &123); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; diff --git a/pool/src/pool/config.rs b/pool/src/pool/config.rs index 4d9d8e4c..c560db04 100644 --- a/pool/src/pool/config.rs +++ b/pool/src/pool/config.rs @@ -1,11 +1,8 @@ use crate::{ - dependencies::BackstopClient, - emissions, errors::PoolError, storage::{self, PoolConfig, ReserveConfig, ReserveData}, }; -use cast::u64; -use soroban_sdk::{panic_with_error, unwrap::UnwrapOptimized, Address, Env, Symbol}; +use soroban_sdk::{panic_with_error, Address, Env, Symbol}; use super::pool::Pool; @@ -113,14 +110,6 @@ pub fn execute_update_reserve(e: &Env, asset: &Address, config: &ReserveConfig) storage::set_res_config(e, asset, &new_config); } -// Update the pool emission information from the backstop -pub fn update_pool_emissions(e: &Env) -> u64 { - let backstop_address = storage::get_backstop(e); - let backstop_client = BackstopClient::new(e, &backstop_address); - let (pool_eps, next_exp) = backstop_client.pool_eps(&e.current_contract_address()); - emissions::update_emissions_cycle(e, next_exp, u64(pool_eps).unwrap_optimized()) -} - #[allow(clippy::zero_prefixed_literal)] fn require_valid_reserve_metadata(e: &Env, metadata: &ReserveConfig) { if metadata.decimals > 18 @@ -147,13 +136,13 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let admin = Address::random(&e); + let admin = Address::generate(&e); let name = Symbol::new(&e, "pool_name"); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let bstop_rate = 0_100_000_000u64; - let backstop_address = Address::random(&e); - let blnd_id = Address::random(&e); - let usdc_id = Address::random(&e); + let backstop_address = Address::generate(&e); + let blnd_id = Address::generate(&e); + let usdc_id = Address::generate(&e); e.as_contract(&pool, || { execute_initialize( @@ -184,7 +173,7 @@ mod tests { let pool = testutils::create_pool(&e); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -207,7 +196,7 @@ mod tests { let pool = testutils::create_pool(&e); let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -222,7 +211,7 @@ mod tests { fn test_initialize_reserve() { let e = Env::default(); let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (asset_id_0, _) = testutils::create_token_contract(&e, &bombadil); let (asset_id_1, _) = testutils::create_token_contract(&e, &bombadil); @@ -264,7 +253,7 @@ mod tests { fn test_initialize_reserve_blocks_duplicates() { let e = Env::default(); let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (asset_id, _) = testutils::create_token_contract(&e, &bombadil); let metadata = ReserveConfig { @@ -292,7 +281,7 @@ mod tests { fn test_initialize_reserve_validates_metadata() { let e = Env::default(); let pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (asset_id, _) = testutils::create_token_contract(&e, &bombadil); let metadata = ReserveConfig { @@ -325,13 +314,13 @@ mod tests { sequence_number: 100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -356,13 +345,13 @@ mod tests { sequence_number: 100, 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 pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; @@ -403,13 +392,13 @@ mod tests { sequence_number: 100, 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 pool = testutils::create_pool(&e); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -429,7 +418,7 @@ mod tests { }; let pool_config = PoolConfig { - oracle: Address::random(&e), + oracle: Address::generate(&e), bstop_rate: 0_100_000_000, status: 0, }; diff --git a/pool/src/pool/health_factor.rs b/pool/src/pool/health_factor.rs index 4b31e920..c2f5c37d 100644 --- a/pool/src/pool/health_factor.rs +++ b/pool/src/pool/health_factor.rs @@ -1,4 +1,4 @@ -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{panic_with_error, unwrap::UnwrapOptimized, Env}; use crate::{constants::SCALAR_7, errors::PoolError, storage}; @@ -122,7 +122,7 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths(); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); @@ -172,9 +172,9 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { oracle, diff --git a/pool/src/pool/interest.rs b/pool/src/pool/interest.rs index 98741c26..4bb57743 100644 --- a/pool/src/pool/interest.rs +++ b/pool/src/pool/interest.rs @@ -1,5 +1,5 @@ use cast::i128; -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{unwrap::UnwrapOptimized, Env}; use crate::{ @@ -142,9 +142,9 @@ mod tests { sequence_number: 100, 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 (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_6565656, ir_mod, 0); @@ -177,9 +177,9 @@ mod tests { sequence_number: 100, 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 (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_7979797, ir_mod, 0); @@ -212,9 +212,9 @@ mod tests { sequence_number: 100, 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 (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_9696969, ir_mod, 0); @@ -247,9 +247,9 @@ mod tests { sequence_number: 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 (_accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_9696969, ir_mod, 0); @@ -281,9 +281,9 @@ mod tests { sequence_number: 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 (_accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_2020202, ir_mod, 0); @@ -315,9 +315,9 @@ mod tests { sequence_number: 100, 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 (accrual, ir_mod) = calc_accrual(&e, &reserve_config, 0_0500000, ir_mod, 500); diff --git a/pool/src/pool/mod.rs b/pool/src/pool/mod.rs index 4170644c..d501510a 100644 --- a/pool/src/pool/mod.rs +++ b/pool/src/pool/mod.rs @@ -7,7 +7,6 @@ pub use bad_debt::{burn_backstop_bad_debt, transfer_bad_debt_to_backstop}; mod config; pub use config::{ execute_initialize, execute_update_pool, execute_update_reserve, initialize_reserve, - update_pool_emissions, }; mod health_factor; diff --git a/pool/src/pool/pool.rs b/pool/src/pool/pool.rs index e1e5e729..d29e47fd 100644 --- a/pool/src/pool/pool.rs +++ b/pool/src/pool/pool.rs @@ -132,14 +132,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -192,14 +192,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, reserve_data) = testutils::default_reserve_meta(); @@ -263,7 +263,7 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let pool_config = PoolConfig { oracle, bstop_rate: 0_200_000_000, @@ -282,7 +282,7 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let pool_config = PoolConfig { oracle, bstop_rate: 0_200_000_000, @@ -341,7 +341,7 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let pool_config = PoolConfig { oracle, bstop_rate: 0_200_000_000, @@ -361,7 +361,7 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let pool_config = PoolConfig { oracle, bstop_rate: 0_200_000_000, @@ -380,7 +380,7 @@ mod tests { let e = Env::default(); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let pool_config = PoolConfig { oracle, bstop_rate: 0_200_000_000, @@ -406,9 +406,9 @@ mod tests { let pool = testutils::create_pool(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); oracle_client.set_data( - &Address::random(&e), - &Asset::Stellar(Address::random(&e)), - &vec![&e, Asset::Stellar(Address::random(&e))], + &Address::generate(&e), + &Asset::Stellar(Address::generate(&e)), + &vec![&e, Asset::Stellar(Address::generate(&e))], &7, &300, ); @@ -431,10 +431,10 @@ mod tests { let e = Env::default(); e.mock_all_auths_allowing_non_root_auth(); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let asset_0 = Address::random(&e); - let asset_1 = Address::random(&e); + let asset_0 = Address::generate(&e); + let asset_1 = Address::generate(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); oracle_client.set_data( @@ -484,14 +484,14 @@ mod tests { sequence_number: 1234, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let asset = Address::random(&e); + let asset = Address::generate(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); oracle_client.set_data( &bombadil, diff --git a/pool/src/pool/reserve.rs b/pool/src/pool/reserve.rs index e67e82f7..6533a41c 100644 --- a/pool/src/pool/reserve.rs +++ b/pool/src/pool/reserve.rs @@ -1,6 +1,6 @@ use cast::i128; -use fixed_point_math::FixedPoint; use sep_41_token::TokenClient; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{contracttype, panic_with_error, unwrap::UnwrapOptimized, Address, Env}; use crate::{ @@ -248,14 +248,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); @@ -296,14 +296,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); @@ -344,14 +344,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); @@ -392,14 +392,14 @@ mod tests { sequence_number: 123456, 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 bombadil = Address::generate(&e); let pool = testutils::create_pool(&e); - let oracle = Address::random(&e); + let oracle = Address::generate(&e); let (underlying, _) = testutils::create_token_contract(&e, &bombadil); let (reserve_config, mut reserve_data) = testutils::default_reserve_meta(); diff --git a/pool/src/pool/status.rs b/pool/src/pool/status.rs index cfc5e447..51ab8682 100644 --- a/pool/src/pool/status.rs +++ b/pool/src/pool/status.rs @@ -92,10 +92,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); @@ -132,49 +132,49 @@ mod tests { }); } - // #[test] - // #[should_panic(expected = "Error(Contract, #11)")] - // fn test_set_pool_status_blocks_without_backstop_minimum() { - // let e = Env::default(); - // e.budget().reset_unlimited(); - // e.mock_all_auths_allowing_non_root_auth(); - // let pool_id = create_pool(&e); - // let oracle_id = Address::random(&e); - - // let bombadil = Address::random(&e); - // let samwise = Address::random(&e); - - // let (blnd, blnd_client) = create_token_contract(&e, &bombadil); - // let (usdc, usdc_client) = create_token_contract(&e, &bombadil); - // let (lp_token, lp_token_client) = create_comet_lp_pool(&e, &bombadil, &blnd, &usdc); - // let (backstop_id, backstop_client) = create_backstop(&e); - // setup_backstop(&e, &pool_id, &backstop_id, &lp_token, &usdc, &blnd); - - // // mint lp tokens - under limit - // blnd_client.mint(&samwise, &400_001_0000000); - // blnd_client.approve(&samwise, &lp_token, &i128::MAX, &99999); - // usdc_client.mint(&samwise, &10_001_0000000); - // usdc_client.approve(&samwise, &lp_token, &i128::MAX, &99999); - // lp_token_client.join_pool( - // &40_000_0000000, - // &vec![&e, 400_001_0000000, 10_001_0000000], - // &samwise, - // ); - // backstop_client.deposit(&samwise, &pool_id, &40_000_0000000); - // backstop_client.update_tkn_val(); - - // let pool_config = PoolConfig { - // oracle: oracle_id, - // bstop_rate: 0, - // status: 1, - // }; - // e.as_contract(&pool_id, || { - // storage::set_admin(&e, &bombadil); - // storage::set_pool_config(&e, &pool_config); - - // set_pool_status(&e, 0); - // }); - // } + #[test] + #[should_panic(expected = "Error(Contract, #11)")] + fn test_set_pool_status_blocks_without_backstop_minimum() { + let e = Env::default(); + e.budget().reset_unlimited(); + e.mock_all_auths_allowing_non_root_auth(); + let pool_id = create_pool(&e); + let oracle_id = Address::generate(&e); + + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + + let (blnd, blnd_client) = create_token_contract(&e, &bombadil); + let (usdc, usdc_client) = create_token_contract(&e, &bombadil); + let (lp_token, lp_token_client) = create_comet_lp_pool(&e, &bombadil, &blnd, &usdc); + let (backstop_id, backstop_client) = create_backstop(&e); + setup_backstop(&e, &pool_id, &backstop_id, &lp_token, &usdc, &blnd); + + // mint lp tokens - under limit + blnd_client.mint(&samwise, &400_001_0000000); + blnd_client.approve(&samwise, &lp_token, &i128::MAX, &99999); + usdc_client.mint(&samwise, &10_001_0000000); + usdc_client.approve(&samwise, &lp_token, &i128::MAX, &99999); + lp_token_client.join_pool( + &40_000_0000000, + &vec![&e, 400_001_0000000, 10_001_0000000], + &samwise, + ); + backstop_client.deposit(&samwise, &pool_id, &40_000_0000000); + backstop_client.update_tkn_val(); + + let pool_config = PoolConfig { + oracle: oracle_id, + bstop_rate: 0, + status: 1, + }; + e.as_contract(&pool_id, || { + storage::set_admin(&e, &bombadil); + storage::set_pool_config(&e, &pool_config); + + set_pool_status(&e, 0); + }); + } #[test] fn test_update_pool_status_active() { @@ -182,10 +182,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); @@ -229,10 +229,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); @@ -276,10 +276,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); @@ -324,10 +324,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); @@ -465,10 +465,10 @@ mod tests { e.budget().reset_unlimited(); e.mock_all_auths_allowing_non_root_auth(); let pool_id = create_pool(&e); - let oracle_id = Address::random(&e); + let oracle_id = Address::generate(&e); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); let (blnd, blnd_client) = create_token_contract(&e, &bombadil); let (usdc, usdc_client) = create_token_contract(&e, &bombadil); diff --git a/pool/src/pool/submit.rs b/pool/src/pool/submit.rs index a3c49779..bd8464a8 100644 --- a/pool/src/pool/submit.rs +++ b/pool/src/pool/submit.rs @@ -79,15 +79,15 @@ mod tests { sequence_number: 1234, 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 samwise = Address::random(&e); - let frodo = Address::random(&e); - let merry = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); + let merry = Address::generate(&e); let pool = testutils::create_pool(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); @@ -167,10 +167,10 @@ mod tests { let e = Env::default(); e.mock_all_auths(); - let bombadil = Address::random(&e); - let samwise = Address::random(&e); - let frodo = Address::random(&e); - let merry = Address::random(&e); + let bombadil = Address::generate(&e); + let samwise = Address::generate(&e); + let frodo = Address::generate(&e); + let merry = Address::generate(&e); let pool = testutils::create_pool(&e); let (oracle, oracle_client) = testutils::create_mock_oracle(&e); @@ -203,9 +203,9 @@ mod tests { sequence_number: 1234, 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 pool_config = PoolConfig { oracle, diff --git a/pool/src/pool/user.rs b/pool/src/pool/user.rs index b23c92a0..d755ce2f 100644 --- a/pool/src/pool/user.rs +++ b/pool/src/pool/user.rs @@ -211,7 +211,7 @@ mod tests { use crate::{ storage, testutils, ReserveEmissionsConfig, ReserveEmissionsData, UserEmissionData, }; - use fixed_point_math::FixedPoint; + use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ map, testutils::{Address as _, Ledger, LedgerInfo}, @@ -220,7 +220,7 @@ mod tests { #[test] fn test_load_and_store() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let user = User { @@ -245,7 +245,7 @@ mod tests { #[test] fn test_liabilities() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -285,7 +285,7 @@ mod tests { #[test] fn test_add_liabilities_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -294,9 +294,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -354,7 +354,7 @@ mod tests { #[test] fn test_remove_liabilities_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -363,9 +363,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -422,7 +422,7 @@ mod tests { #[should_panic(expected = "Error(Contract, #4)")] fn test_remove_liabilities_over_balance_panics() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -441,7 +441,7 @@ mod tests { #[test] fn test_collateral() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -481,7 +481,7 @@ mod tests { #[test] fn test_add_collateral_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -490,9 +490,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -549,7 +549,7 @@ mod tests { #[test] fn test_remove_collateral_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -558,9 +558,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -618,7 +618,7 @@ mod tests { #[should_panic(expected = "Error(Contract, #4)")] fn test_remove_collateral_over_balance_panics() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -638,7 +638,7 @@ mod tests { #[test] fn test_supply() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -678,7 +678,7 @@ mod tests { #[test] fn test_add_supply_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -687,9 +687,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -746,7 +746,7 @@ mod tests { #[test] fn test_remove_supply_accrues_emissions() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); e.ledger().set(LedgerInfo { @@ -755,9 +755,9 @@ mod tests { timestamp: 10001000, 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 mut reserve_0 = testutils::default_reserve(&e); @@ -815,7 +815,7 @@ mod tests { #[should_panic(expected = "Error(Contract, #4)")] fn test_remove_supply_over_balance_panics() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); @@ -835,7 +835,7 @@ mod tests { #[test] fn test_total_supply() { let e = Env::default(); - let samwise = Address::random(&e); + let samwise = Address::generate(&e); let pool = testutils::create_pool(&e); let mut reserve_0 = testutils::default_reserve(&e); diff --git a/pool/src/storage.rs b/pool/src/storage.rs index aeb740fc..bf4e8ac1 100644 --- a/pool/src/storage.rs +++ b/pool/src/storage.rs @@ -87,6 +87,15 @@ pub struct UserEmissionData { /********** Storage Key Types **********/ +const ADMIN_KEY: &str = "Admin"; +const NAME_KEY: &str = "Name"; +const BACKSTOP_KEY: &str = "Backstop"; +const BLND_TOKEN_KEY: &str = "BLNDTkn"; +const USDC_TOKEN_KEY: &str = "USDCTkn"; +const POOL_CONFIG_KEY: &str = "Config"; +const RES_LIST_KEY: &str = "ResList"; +const POOL_EMIS_KEY: &str = "PoolEmis"; + #[derive(Clone)] #[contracttype] pub struct UserReserveKey { @@ -126,10 +135,10 @@ pub enum PoolDataKey { /********** Storage **********/ /// 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 @@ -143,7 +152,7 @@ fn get_persistent_default, V: TryFromVal>( 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 @@ -179,7 +188,7 @@ pub fn set_user_positions(e: &Env, user: &Address, positions: &Positions) { .set::(&key, positions); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_USER, LEDGER_BUMP_USER); + .extend_ttl(&key, LEDGER_THRESHOLD_USER, LEDGER_BUMP_USER); } /********** Admin **********/ @@ -191,7 +200,7 @@ pub fn set_user_positions(e: &Env, user: &Address, positions: &Positions) { pub fn get_admin(e: &Env) -> Address { e.storage() .instance() - .get(&Symbol::new(e, "Admin")) + .get(&Symbol::new(e, ADMIN_KEY)) .unwrap_optimized() } @@ -202,12 +211,12 @@ pub fn get_admin(e: &Env) -> Address { pub fn set_admin(e: &Env, new_admin: &Address) { e.storage() .instance() - .set::(&Symbol::new(e, "Admin"), new_admin); + .set::(&Symbol::new(e, ADMIN_KEY), new_admin); } /// Checks if an admin is set pub fn has_admin(e: &Env) -> bool { - e.storage().instance().has(&Symbol::new(e, "Admin")) + e.storage().instance().has(&Symbol::new(e, ADMIN_KEY)) } /********** Metadata **********/ @@ -219,7 +228,7 @@ pub fn has_admin(e: &Env) -> bool { pub fn set_name(e: &Env, name: &Symbol) { e.storage() .instance() - .set::(&Symbol::new(e, "Name"), name); + .set::(&Symbol::new(e, NAME_KEY), name); } /********** Backstop **********/ @@ -231,7 +240,7 @@ pub fn set_name(e: &Env, name: &Symbol) { pub fn get_backstop(e: &Env) -> Address { e.storage() .instance() - .get(&Symbol::new(e, "Backstop")) + .get(&Symbol::new(e, BACKSTOP_KEY)) .unwrap_optimized() } @@ -242,7 +251,7 @@ pub fn get_backstop(e: &Env) -> Address { pub fn set_backstop(e: &Env, backstop: &Address) { e.storage() .instance() - .set::(&Symbol::new(e, "Backstop"), backstop); + .set::(&Symbol::new(e, BACKSTOP_KEY), backstop); } /********** External Token Contracts **********/ @@ -251,7 +260,7 @@ pub fn set_backstop(e: &Env, backstop: &Address) { 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() } @@ -262,14 +271,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() } @@ -280,7 +289,7 @@ 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); } /********** Pool Config **********/ @@ -292,7 +301,7 @@ pub fn set_usdc_token(e: &Env, usdc_token_id: &Address) { pub fn get_pool_config(e: &Env) -> PoolConfig { e.storage() .instance() - .get(&Symbol::new(e, "PoolConfig")) + .get(&Symbol::new(e, POOL_CONFIG_KEY)) .unwrap_optimized() } @@ -303,7 +312,7 @@ pub fn get_pool_config(e: &Env) -> PoolConfig { pub fn set_pool_config(e: &Env, config: &PoolConfig) { e.storage() .instance() - .set::(&Symbol::new(e, "PoolConfig"), config); + .set::(&Symbol::new(e, POOL_CONFIG_KEY), config); } /********** Reserve Config (ResConfig) **********/ @@ -319,7 +328,7 @@ pub fn get_res_config(e: &Env, asset: &Address) -> ReserveConfig { let key = PoolDataKey::ResConfig(asset.clone()); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); e.storage() .persistent() .get::(&key) @@ -338,7 +347,7 @@ pub fn set_res_config(e: &Env, asset: &Address, config: &ReserveConfig) { .set::(&key, config); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /// Checks if a reserve exists for an asset @@ -363,7 +372,7 @@ pub fn get_res_data(e: &Env, asset: &Address) -> ReserveData { let key = PoolDataKey::ResData(asset.clone()); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); e.storage() .persistent() .get::(&key) @@ -382,17 +391,16 @@ pub fn set_res_data(e: &Env, asset: &Address, data: &ReserveData) { .set::(&key, data); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /********** Reserve List (ResList) **********/ /// Fetch the list of reserves pub fn get_res_list(e: &Env) -> Vec
{ - let key = Symbol::new(e, "ResList"); get_persistent_default( e, - &key, + &Symbol::new(e, RES_LIST_KEY), vec![e], LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED, @@ -415,13 +423,14 @@ pub fn push_res_list(e: &Env, asset: &Address) -> u32 { } res_list.push_back(asset.clone()); let new_index = res_list.len() - 1; - let key = Symbol::new(e, "ResList"); - e.storage() - .persistent() - .set::>(&key, &res_list); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .set::>(&Symbol::new(e, RES_LIST_KEY), &res_list); + e.storage().persistent().extend_ttl( + &Symbol::new(e, RES_LIST_KEY), + LEDGER_THRESHOLD_SHARED, + LEDGER_BUMP_SHARED, + ); new_index } @@ -458,7 +467,7 @@ pub fn set_res_emis_config( .set::(&key, res_emis_config); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /// Fetch the emission data for the reserve b or d token @@ -476,15 +485,6 @@ pub fn get_res_emis_data(e: &Env, res_token_index: &u32) -> Option bool { - let key = PoolDataKey::EmisData(*res_token_index); - e.storage().persistent().has(&key) -} - /// Set the emission data for the reserve b or d token /// /// ### Arguments @@ -497,7 +497,7 @@ pub fn set_res_emis_data(e: &Env, res_token_index: &u32, res_emis_data: &Reserve .set::(&key, res_emis_data); e.storage() .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /********** User Emissions **********/ @@ -545,10 +545,9 @@ pub fn set_user_emissions(e: &Env, user: &Address, res_token_index: &u32, data: /// Fetch the pool reserve emissions pub fn get_pool_emissions(e: &Env) -> Map { - let key = Symbol::new(e, "PoolEmis"); get_persistent_default::>( e, - &key, + &Symbol::new(e, POOL_EMIS_KEY), map![e], LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED, @@ -558,35 +557,17 @@ pub fn get_pool_emissions(e: &Env) -> Map { /// Set the pool reserve emissions /// /// ### Arguments -/// * `emissions` - The map of emissions by reserve token id to EPS +/// * `emissions` - The map of emissions by reserve token id to share of emissions as +/// a percentage of 1e7 (e.g. 15% = 1500000) pub fn set_pool_emissions(e: &Env, emissions: &Map) { - let key = Symbol::new(e, "PoolEmis"); e.storage() .persistent() - .set::>(&key, emissions); - e.storage() - .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); -} - -/// Fetch the pool emission expiration timestamps -pub fn get_pool_emissions_expiration(e: &Env) -> u64 { - let key = Symbol::new(e, "EmisExp"); - get_persistent_default(e, &key, 0u64, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED) -} - -/// Set the pool emission configuration -/// -/// ### Arguments -/// * `expiration` - The pool's emission configuration -pub fn set_pool_emissions_expiration(e: &Env, expiration: &u64) { - let key = Symbol::new(e, "EmisExp"); - e.storage() - .persistent() - .set::(&key, expiration); - e.storage() - .persistent() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .set::>(&Symbol::new(e, POOL_EMIS_KEY), emissions); + e.storage().persistent().extend_ttl( + &Symbol::new(e, POOL_EMIS_KEY), + LEDGER_THRESHOLD_SHARED, + LEDGER_BUMP_SHARED, + ); } /********** Auctions ***********/ @@ -639,7 +620,7 @@ pub fn set_auction(e: &Env, auction_type: &u32, user: &Address, auction_data: &A .set::(&key, auction_data); e.storage() .temporary() - .bump(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); + .extend_ttl(&key, LEDGER_THRESHOLD_SHARED, LEDGER_BUMP_SHARED); } /// Remove an auction diff --git a/pool/src/testutils.rs b/pool/src/testutils.rs index 8d60d4f6..db27867b 100644 --- a/pool/src/testutils.rs +++ b/pool/src/testutils.rs @@ -6,9 +6,10 @@ use crate::{ storage::{self, ReserveConfig, ReserveData}, PoolContract, }; -use fixed_point_math::FixedPoint; +use emitter::{EmitterClient, EmitterContract}; use sep_40_oracle::testutils::{MockPriceOracleClient, MockPriceOracleWASM}; use sep_41_token::testutils::{MockTokenClient, MockTokenWASM}; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ map, testutils::Address as _, unwrap::UnwrapOptimized, vec, Address, Env, IntoVal, }; @@ -30,7 +31,7 @@ pub(crate) fn create_token_contract<'a>( e: &Env, admin: &Address, ) -> (Address, MockTokenClient<'a>) { - let contract_address = Address::random(e); + let contract_address = Address::generate(e); e.register_contract_wasm(&contract_address, MockTokenWASM); let client = MockTokenClient::new(e, &contract_address); client.initialize(admin, &7, &"unit".into_val(e), &"test".into_val(e)); @@ -83,6 +84,20 @@ pub(crate) fn create_mock_pool_factory(e: &Env) -> (Address, MockPoolFactoryClie ) } +//***** Pool Factory ****** + +pub(crate) fn create_emitter<'a>( + e: &Env, + backstop_id: &Address, + backstop_token: &Address, + blnd_token: &Address, +) -> (Address, EmitterClient<'a>) { + let contract_address = e.register_contract(None, EmitterContract {}); + let client = EmitterClient::new(e, &contract_address); + client.initialize(blnd_token, backstop_id, backstop_token); + (contract_address.clone(), client) +} + //***** Backstop ****** mod comet { @@ -107,8 +122,10 @@ pub(crate) fn setup_backstop( ) { let (pool_factory, mock_pool_factory_client) = create_mock_pool_factory(e); mock_pool_factory_client.set_pool(pool_address); + let (emitter, _) = create_emitter(e, backstop_id, backstop_token, blnd_token); BackstopClient::new(e, backstop_id).initialize( backstop_token, + &emitter, usdc_token, blnd_token, &pool_factory, @@ -132,7 +149,7 @@ pub(crate) fn create_comet_lp_pool<'a>( blnd_token: &Address, usdc_token: &Address, ) -> (Address, comet::Client<'a>) { - let contract_address = Address::random(e); + let contract_address = Address::generate(e); e.register_contract_wasm(&contract_address, comet::WASM); let client = comet::Client::new(e, &contract_address); @@ -144,7 +161,7 @@ pub(crate) fn create_comet_lp_pool<'a>( blnd_client.approve(&admin, &contract_address, &2_000_0000000, &exp_ledger); usdc_client.approve(&admin, &contract_address, &2_000_0000000, &exp_ledger); - client.init(&Address::random(e), &admin); + client.init(&Address::generate(e), &admin); client.bundle_bind( &vec![e, blnd_token.clone(), usdc_token.clone()], &vec![e, 1_000_0000000, 25_0000000], @@ -166,7 +183,7 @@ pub(crate) fn create_comet_lp_pool<'a>( pub(crate) fn default_reserve(e: &Env) -> Reserve { Reserve { - asset: Address::random(e), + asset: Address::generate(e), index: 0, l_factor: 0_7500000, c_factor: 0_7500000, diff --git a/test-suites/Cargo.toml b/test-suites/Cargo.toml index dcd39dee..769426b1 100644 --- a/test-suites/Cargo.toml +++ b/test-suites/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } rand = { version = "0.7.3" } -fixed-point-math = { workspace = true } +soroban-fixed-point-math = { workspace = true } pool = { path = "../pool", features = ["testutils"] } backstop = { path = "../backstop", features = ["testutils"] } pool-factory = { path = "../pool-factory", features = ["testutils"] } diff --git a/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs b/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs index 7952c18d..9bae2005 100644 --- a/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs +++ b/test-suites/fuzz/fuzz_targets/fuzz_pool_general.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![no_main] -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use fuzz_common::{ verify_contract_result, Borrow, ClaimPool, NatI128, PassTime, Repay, Supply, Withdraw, }; @@ -51,9 +51,9 @@ fuzz_target!(|input: Input| { let mut fixture = create_fixture_with_data(false); // Create two new users - let sam = Address::random(&fixture.env); + let sam = Address::generate(&fixture.env); fixture.users.push(sam.clone()); - let merry = Address::random(&fixture.env); + let merry = Address::generate(&fixture.env); fixture.users.push(merry.clone()); // Mint users tokens diff --git a/test-suites/fuzz/lib.rs b/test-suites/fuzz/lib.rs index 3cd48d64..18de93d0 100644 --- a/test-suites/fuzz/lib.rs +++ b/test-suites/fuzz/lib.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![no_main] -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use lending_pool::{PoolState, PositionData, Request}; use libfuzzer_sys::fuzz_target; use soroban_sdk::arbitrary::arbitrary::{self, Arbitrary, Unstructured}; diff --git a/test-suites/src/assertions.rs b/test-suites/src/assertions.rs index 63f192d6..718a8ccb 100644 --- a/test-suites/src/assertions.rs +++ b/test-suites/src/assertions.rs @@ -1,5 +1,5 @@ use crate::test_fixture::SCALAR_7; -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; pub fn assert_approx_eq_abs(a: i128, b: i128, delta: i128) { assert!( diff --git a/test-suites/src/backstop.rs b/test-suites/src/backstop.rs index ee40b1f4..6515285e 100644 --- a/test-suites/src/backstop.rs +++ b/test-suites/src/backstop.rs @@ -6,7 +6,7 @@ mod backstop_contract_wasm { use backstop::{BackstopClient, BackstopContract}; pub fn create_backstop<'a>(e: &Env, wasm: bool) -> (Address, BackstopClient<'a>) { - let contract_id = Address::random(e); + let contract_id = Address::generate(e); if wasm { e.register_contract_wasm(&contract_id, backstop_contract_wasm::WASM); } else { diff --git a/test-suites/src/emitter.rs b/test-suites/src/emitter.rs index 54d4246a..3d6effaa 100644 --- a/test-suites/src/emitter.rs +++ b/test-suites/src/emitter.rs @@ -7,7 +7,7 @@ mod emitter_contract { use emitter::{EmitterClient, EmitterContract}; pub fn create_emitter<'a>(e: &Env, wasm: bool) -> (Address, EmitterClient<'a>) { - let contract_id = Address::random(e); + let contract_id = Address::generate(e); if wasm { e.register_contract_wasm(&contract_id, emitter_contract::WASM); } else { diff --git a/test-suites/src/liquidity_pool.rs b/test-suites/src/liquidity_pool.rs index ba078a2e..9fcbe8b8 100644 --- a/test-suites/src/liquidity_pool.rs +++ b/test-suites/src/liquidity_pool.rs @@ -22,7 +22,7 @@ pub(crate) fn create_lp_pool<'a>( token_1: &Address, token_2: &Address, ) -> (Address, LPClient<'a>) { - let contract_address = Address::random(e); + let contract_address = Address::generate(e); e.register_contract_wasm(&contract_address, LP_WASM); let client = LPClient::new(e, &contract_address); @@ -33,7 +33,7 @@ pub(crate) fn create_lp_pool<'a>( token_1_client.approve(&admin, &contract_address, &1_000_0000000, &5356700); token_2_client.approve(&admin, &contract_address, &1_000_0000000, &5356700); - client.init(&Address::random(e), &admin); + client.init(&Address::generate(e), &admin); client.bundle_bind( &vec![e, token_1.clone(), token_2.clone()], &vec![e, 1_000_0000000, 25_0000000], diff --git a/test-suites/src/oracle.rs b/test-suites/src/oracle.rs index 15a760c9..f9b43814 100644 --- a/test-suites/src/oracle.rs +++ b/test-suites/src/oracle.rs @@ -3,7 +3,7 @@ use soroban_sdk::{testutils::Address as _, Address, Env}; use sep_40_oracle::testutils::{MockPriceOracleClient, MockPriceOracleWASM}; pub fn create_mock_oracle<'a>(e: &Env) -> (Address, MockPriceOracleClient<'a>) { - let contract_id = Address::random(e); + let contract_id = Address::generate(e); e.register_contract_wasm(&contract_id, MockPriceOracleWASM); ( contract_id.clone(), diff --git a/test-suites/src/pool_factory.rs b/test-suites/src/pool_factory.rs index cf0cccfa..c90d05fb 100644 --- a/test-suites/src/pool_factory.rs +++ b/test-suites/src/pool_factory.rs @@ -10,7 +10,7 @@ use pool_factory::PoolFactoryClient; use mock_pool_factory::MockPoolFactory; pub fn create_pool_factory<'a>(e: &Env, wasm: bool) -> (Address, PoolFactoryClient<'a>) { - let contract_id = Address::random(e); + let contract_id = Address::generate(e); if wasm { e.register_contract_wasm(&contract_id, pool_factory_contract::WASM); } else { diff --git a/test-suites/src/setup.rs b/test-suites/src/setup.rs index 79d13121..9c012c06 100644 --- a/test-suites/src/setup.rs +++ b/test-suites/src/setup.rs @@ -52,7 +52,7 @@ pub fn create_fixture_with_data<'a>(wasm: bool) -> TestFixture<'a> { pool_fixture.pool.set_emissions_config(&reserve_emissions); // mint whale tokens - let frodo = Address::random(&fixture.env); + let frodo = Address::generate(&fixture.env); fixture.users.push(frodo.clone()); fixture.tokens[TokenIndex::STABLE].mint(&frodo, &(100_000 * 10i128.pow(6))); fixture.tokens[TokenIndex::XLM].mint(&frodo, &(1_000_000 * SCALAR_7)); @@ -80,29 +80,29 @@ pub fn create_fixture_with_data<'a>(wasm: bool) -> TestFixture<'a> { fixture.backstop.update_tkn_val(); fixture .backstop - .add_reward(&pool_fixture.pool.address, &Address::random(&fixture.env)); + .add_reward(&pool_fixture.pool.address, &Address::generate(&fixture.env)); pool_fixture.pool.update_status(); // enable emissions fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); - pool_fixture.pool.update_emissions(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); fixture.jump(60); - fixture.tokens[TokenIndex::STABLE].approve( - &frodo, - &pool_fixture.pool.address, - &i128::MAX, - &50000, - ); - fixture.tokens[TokenIndex::WETH].approve( - &frodo, - &pool_fixture.pool.address, - &i128::MAX, - &50000, - ); - fixture.tokens[TokenIndex::XLM].approve(&frodo, &pool_fixture.pool.address, &i128::MAX, &50000); + // fixture.tokens[TokenIndex::STABLE].approve( + // &frodo, + // &pool_fixture.pool.address, + // &i128::MAX, + // &(fixture.env.ledger().sequence() + 100), + // ); + // fixture.tokens[TokenIndex::WETH].approve( + // &frodo, + // &pool_fixture.pool.address, + // &i128::MAX, + // &(fixture.env.ledger().sequence() + 100), + // ); + // fixture.tokens[TokenIndex::XLM].approve(&frodo, &pool_fixture.pool.address, &i128::MAX, &50000); // supply and borrow STABLE for 80% utilization (close to target) let requests: Vec = vec![ @@ -205,13 +205,6 @@ mod tests { ); // validate emissions are turned on - assert_eq!( - ( - 0_300_0000, - fixture.env.ledger().timestamp() - 60 * 61 + 7 * 24 * 60 * 60 - ), - fixture.backstop.pool_eps(&pool_fixture.pool.address) - ); let (emis_config, emis_data) = fixture.read_reserve_emissions(0, TokenIndex::STABLE, 0); assert_eq!( emis_data.last_time, @@ -219,6 +212,10 @@ mod tests { ); assert_eq!(emis_data.index, 0); assert_eq!(0_180_0000, emis_config.eps); + assert_eq!( + fixture.env.ledger().timestamp() + 7 * 24 * 60 * 60 - 60 * 61, + emis_config.expiration + ) } #[test] @@ -261,13 +258,6 @@ mod tests { ); // validate emissions are turned on - assert_eq!( - ( - 0_300_0000, - fixture.env.ledger().timestamp() - 60 * 61 + 7 * 24 * 60 * 60 - ), - fixture.backstop.pool_eps(&pool_fixture.pool.address) - ); let (emis_config, emis_data) = fixture.read_reserve_emissions(0, TokenIndex::STABLE, 0); assert_eq!( emis_data.last_time, @@ -275,5 +265,9 @@ mod tests { ); assert_eq!(emis_data.index, 0); assert_eq!(0_180_0000, emis_config.eps); + assert_eq!( + fixture.env.ledger().timestamp() + 7 * 24 * 60 * 60 - 60 * 61, + emis_config.expiration + ) } } diff --git a/test-suites/src/test_fixture.rs b/test-suites/src/test_fixture.rs index 9306362a..f53fef33 100644 --- a/test-suites/src/test_fixture.rs +++ b/test-suites/src/test_fixture.rs @@ -68,17 +68,17 @@ impl TestFixture<'_> { e.mock_all_auths(); e.budget().reset_unlimited(); - let bombadil = Address::random(&e); + let bombadil = Address::generate(&e); e.ledger().set(LedgerInfo { timestamp: 1441065600, // Sept 1st, 2015 (backstop epoch) protocol_version: 20, - sequence_number: 5000000, + sequence_number: 150, network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 999999, - min_persistent_entry_expiration: 999999, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 500000, + min_persistent_entry_ttl: 500000, + max_entry_ttl: 9999999, }); // deploy tokens @@ -93,14 +93,23 @@ impl TestFixture<'_> { let (emitter_id, emitter_client) = create_emitter(&e, wasm); let (pool_factory_id, _) = create_pool_factory(&e, wasm); + // deploy external contracts + let (lp, lp_client) = create_lp_pool(&e, &bombadil, &blnd_id, &usdc_id); + // initialize emitter blnd_client.mint(&bombadil, &(10_000_000 * SCALAR_7)); blnd_client.set_admin(&emitter_id); - emitter_client.initialize(&backstop_id, &blnd_id); + emitter_client.initialize(&blnd_id, &backstop_id, &lp); // initialize backstop - let (lp, lp_client) = create_lp_pool(&e, &bombadil, &blnd_id, &usdc_id); - backstop_client.initialize(&lp, &usdc_id, &blnd_id, &pool_factory_id, &Map::new(&e)); + backstop_client.initialize( + &lp, + &emitter_id, + &usdc_id, + &blnd_id, + &pool_factory_id, + &Map::new(&e), + ); // initialize pool factory let pool_hash = e.deployer().upload_contract_wasm(POOL_WASM); @@ -136,19 +145,7 @@ impl TestFixture<'_> { 1_0000000 // stable ]); - // pass 1 day - e.ledger().set(LedgerInfo { - timestamp: 1441152000, - protocol_version: 20, - sequence_number: 150, - network_id: Default::default(), - base_reserve: 10, - min_temp_entry_expiration: 999999, - min_persistent_entry_expiration: 999999, - max_entry_expiration: u32::MAX, - }); - - TestFixture { + let fixture = TestFixture { env: e, bombadil, users: vec![], @@ -165,7 +162,9 @@ impl TestFixture<'_> { xlm_client, stable_client, ], - } + }; + fixture.jump(7 * 24 * 60 * 60); + fixture } pub fn create_pool(&mut self, name: Symbol, backstop_take_rate: u64) { @@ -205,7 +204,7 @@ impl TestFixture<'_> { self.env .storage() .instance() - .get(&Symbol::new(&self.env, "PoolConfig")) + .get(&Symbol::new(&self.env, "Config")) .unwrap() }) } @@ -282,9 +281,9 @@ impl TestFixture<'_> { sequence_number: self.env.ledger().sequence(), network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 999999, - min_persistent_entry_expiration: 999999, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 999999, + min_persistent_entry_ttl: 999999, + max_entry_ttl: 9999999, }); } @@ -296,9 +295,9 @@ impl TestFixture<'_> { sequence_number: self.env.ledger().sequence().saturating_add(blocks as u32), network_id: Default::default(), base_reserve: 10, - min_temp_entry_expiration: 999999, - min_persistent_entry_expiration: 999999, - max_entry_expiration: u32::MAX, + min_temp_entry_ttl: 999999, + min_persistent_entry_ttl: 999999, + max_entry_ttl: 9999999, }); } } diff --git a/test-suites/src/token.rs b/test-suites/src/token.rs index 8984d809..f4382c94 100644 --- a/test-suites/src/token.rs +++ b/test-suites/src/token.rs @@ -15,7 +15,7 @@ pub fn create_token<'a>( decimals: u32, symbol: &str, ) -> (Address, MockTokenClient<'a>) { - let contract_id = Address::random(e); + let contract_id = Address::generate(e); e.register_contract_wasm(&contract_id, MockTokenWASM); let client = MockTokenClient::new(e, &contract_id); client.initialize( diff --git a/test-suites/tests/test_backstop.rs b/test-suites/tests/test_backstop.rs index 38c7404d..427fa1c8 100644 --- a/test-suites/tests/test_backstop.rs +++ b/test-suites/tests/test_backstop.rs @@ -1,6 +1,6 @@ #![cfg(test)] -use fixed_point_math::FixedPoint; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, vec, Address, IntoVal, Map, Symbol, Val, Vec, @@ -20,14 +20,15 @@ fn test_backstop() { let pool = &fixture.pools[0].pool; let bstop_token = &fixture.lp; - let sam = Address::random(&fixture.env); + let sam = Address::generate(&fixture.env); // Verify initialization can't be re-run let result = fixture.backstop.try_initialize( - &Address::random(&fixture.env), - &Address::random(&fixture.env), - &Address::random(&fixture.env), - &Address::random(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), &Map::new(&fixture.env), ); assert!(result.is_err()); @@ -197,7 +198,7 @@ fn test_backstop() { // Start the next emission cycle fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); + fixture.backstop.gulp_emissions(); assert_eq!(fixture.env.auths().len(), 0); // Sam queues 100% of position for withdrawal @@ -260,7 +261,7 @@ fn test_backstop() { // Start the next emission cycle and jump 7 days (13d23hr total emissions for sam) fixture.jump(60 * 60 * 24 * 7); fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); + fixture.backstop.gulp_emissions(); // Sam dequeues half of the withdrawal let amount = 6_250 * SCALAR_7; // shares @@ -312,7 +313,7 @@ fn test_backstop() { // Start the next emission cycle and jump 7 days (20d23hr total emissions for sam) fixture.jump(60 * 60 * 24 * 7); fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); + fixture.backstop.gulp_emissions(); // Backstop loses money let amount = 1_000 * SCALAR_7; diff --git a/test-suites/tests/test_emitter.rs b/test-suites/tests/test_emitter.rs index c6512848..766e5334 100644 --- a/test-suites/tests/test_emitter.rs +++ b/test-suites/tests/test_emitter.rs @@ -1,5 +1,6 @@ #![cfg(test)] +use emitter::Swap; use soroban_sdk::{ testutils::{Address as _, Events}, vec, Address, IntoVal, Symbol, @@ -23,8 +24,9 @@ fn test_emitter() { // Verify initialization can't be re-run let result = fixture.emitter.try_initialize( - &Address::random(&fixture.env), - &Address::random(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), ); assert!(result.is_err()); assert_eq!( @@ -65,19 +67,80 @@ fn test_emitter() { ] ); - // Mint enough tokens to a new backstop address to perform a swap, then swap the backstops + // Mint enough tokens to a new backstop address to perform a swap, then queue the swap let old_backstop_balance = bstop_token.balance(&fixture.backstop.address); - let new_backstop = Address::random(&fixture.env); - fixture.tokens[TokenIndex::BLND].mint(&new_backstop, &(505_001 * SCALAR_7)); - fixture.tokens[TokenIndex::USDC].mint(&new_backstop, &(13_501 * SCALAR_7)); + let new_backstop = Address::generate(&fixture.env); + fixture.tokens[TokenIndex::BLND].mint(&new_backstop, &(600_001 * SCALAR_7)); + fixture.tokens[TokenIndex::USDC].mint(&new_backstop, &(20_501 * SCALAR_7)); fixture.lp.join_pool( &(old_backstop_balance + 1), &vec![&fixture.env, 505_001 * SCALAR_7, 13_501 * SCALAR_7], &new_backstop, ); - fixture.emitter.swap_backstop(&new_backstop); + fixture + .emitter + .queue_swap_backstop(&new_backstop, &fixture.lp.address); + let swap_unlock_time = fixture.env.ledger().timestamp() + 31 * 24 * 60 * 60; assert_eq!(fixture.env.auths().len(), 0); - assert_eq!(fixture.emitter.get_backstop(), new_backstop.clone()); + assert_eq!( + fixture.emitter.get_backstop(), + fixture.backstop.address.clone() + ); + let event = vec![&fixture.env, fixture.env.events().all().last_unchecked()]; + assert_eq!( + event, + vec![ + &fixture.env, + ( + fixture.emitter.address.clone(), + (Symbol::new(&fixture.env, "q_swap"),).into_val(&fixture.env), + Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: fixture.lp.address.clone(), + unlock_time: swap_unlock_time, + } + .into_val(&fixture.env) + ) + ] + ); + + // Let some time go by + fixture.jump(5 * 24 * 60 * 60); + + // Remove tokens from the new backstop and cancel the swap + fixture.lp.transfer(&new_backstop, &fixture.bombadil, &5); + fixture.emitter.cancel_swap_backstop(); + assert_eq!(fixture.env.auths().len(), 0); + assert_eq!( + fixture.emitter.get_backstop(), + fixture.backstop.address.clone() + ); + let event = vec![&fixture.env, fixture.env.events().all().last_unchecked()]; + assert_eq!( + event, + vec![ + &fixture.env, + ( + fixture.emitter.address.clone(), + (Symbol::new(&fixture.env, "del_swap"),).into_val(&fixture.env), + Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: fixture.lp.address.clone(), + unlock_time: swap_unlock_time, + } + .into_val(&fixture.env) + ) + ] + ); + + // Restart the swap, wait for it to unlock, then swap + fixture.lp.transfer(&fixture.bombadil, &new_backstop, &5); + fixture + .emitter + .queue_swap_backstop(&new_backstop, &fixture.lp.address); + let swap_unlock_time = fixture.env.ledger().timestamp() + 31 * 24 * 60 * 60; + fixture.jump(swap_unlock_time + 1); + fixture.emitter.swap_backstop(); let event = vec![&fixture.env, fixture.env.events().all().last_unchecked()]; assert_eq!( event, @@ -86,8 +149,14 @@ fn test_emitter() { ( fixture.emitter.address.clone(), (Symbol::new(&fixture.env, "swap"),).into_val(&fixture.env), - vec![&fixture.env, new_backstop.to_val(),].into_val(&fixture.env) + Swap { + new_backstop: new_backstop.clone(), + new_backstop_token: fixture.lp.address.clone(), + unlock_time: swap_unlock_time, + } + .into_val(&fixture.env) ) ] ); + assert_eq!(fixture.emitter.get_backstop(), new_backstop.clone()); } diff --git a/test-suites/tests/test_liquidation.rs b/test-suites/tests/test_liquidation.rs index 7fccef1d..705f2720 100644 --- a/test-suites/tests/test_liquidation.rs +++ b/test-suites/tests/test_liquidation.rs @@ -1,7 +1,7 @@ #![cfg(test)] use cast::i128; -use fixed_point_math::FixedPoint; use pool::{PoolDataKey, Positions, Request, ReserveConfig, ReserveData}; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ testutils::{Address as AddressTestTrait, Events}, vec, Address, Error, IntoVal, Symbol, Val, Vec, @@ -36,7 +36,7 @@ fn test_liquidations() { .update_reserve(&fixture.tokens[TokenIndex::WETH].address, &weth_config); // Create a user - let samwise = Address::random(&fixture.env); //sam will be supplying XLM and borrowing STABLE + let samwise = Address::generate(&fixture.env); //sam will be supplying XLM and borrowing STABLE // Mint users tokens fixture.tokens[TokenIndex::XLM].mint(&samwise, &(500_000 * SCALAR_7)); @@ -99,8 +99,8 @@ fn test_liquidations() { fixture.jump(60 * 60 * 24 * 7); // Update emissions fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); - pool_fixture.pool.update_emissions(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); } // Start an interest auction // type 2 is an interest auction @@ -938,7 +938,7 @@ fn test_user_restore_position_and_delete_liquidation() { let xlm_pool_index = pool_fixture.reserves[&TokenIndex::XLM]; // Create a user that is supply STABLE (cf = 90%, $1) and borrowing XLM (lf = 75%, $0.10) - let samwise = Address::random(&fixture.env); + let samwise = Address::generate(&fixture.env); fixture.tokens[TokenIndex::STABLE].mint(&samwise, &(1100 * 10i128.pow(6))); // deposit $1k stable and borrow to 90% borrow limit ($810) @@ -978,7 +978,7 @@ fn test_user_restore_position_and_delete_liquidation() { &fixture.env, Request { request_type: 9, - address: Address::random(&fixture.env), + address: Address::generate(&fixture.env), amount: i128::MAX, }, ]; @@ -998,7 +998,7 @@ fn test_user_restore_position_and_delete_liquidation() { }, Request { request_type: 9, - address: Address::random(&fixture.env), + address: Address::generate(&fixture.env), amount: i128::MAX, }, ]; @@ -1015,7 +1015,7 @@ fn test_user_restore_position_and_delete_liquidation() { &fixture.env, Request { request_type: 9, - address: Address::random(&fixture.env), + address: Address::generate(&fixture.env), amount: i128::MAX, }, Request { @@ -1043,7 +1043,7 @@ fn test_user_restore_position_and_delete_liquidation() { }, Request { request_type: 9, - address: Address::random(&fixture.env), + address: Address::generate(&fixture.env), amount: i128::MAX, }, Request { diff --git a/test-suites/tests/test_pool.rs b/test-suites/tests/test_pool.rs index 39d97065..1dd61f21 100644 --- a/test-suites/tests/test_pool.rs +++ b/test-suites/tests/test_pool.rs @@ -1,7 +1,7 @@ #![cfg(test)] -use fixed_point_math::FixedPoint; use pool::{Request, ReserveEmissionMetadata}; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{ testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, vec, Address, IntoVal, Symbol, Val, @@ -25,7 +25,7 @@ fn test_pool_user() { let weth = &fixture.tokens[TokenIndex::WETH]; let weth_scalar: i128 = 10i128.pow(weth.decimals()); - let sam = Address::random(&fixture.env); + let sam = Address::generate(&fixture.env); // Mint sam tokens let mut sam_xlm_balance = 10_000 * SCALAR_7; @@ -357,8 +357,8 @@ fn test_pool_user() { // allow the rest of the emissions period to pass (6 days - 5d23h59m emitted for XLM supply) fixture.jump(6 * 24 * 60 * 60); fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); - pool_fixture.pool.update_emissions(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); assert_eq!(fixture.env.auths().len(), 0); // no auth required to update emissions // Sam repay and withdrawal positions @@ -541,13 +541,13 @@ fn test_pool_config() { // Verify initialize can't be run again let result = pool_fixture.pool.try_initialize( - &Address::random(&fixture.env), + &Address::generate(&fixture.env), &Symbol::new(&fixture.env, "teapot"), - &Address::random(&fixture.env), + &Address::generate(&fixture.env), &10000, - &Address::random(&fixture.env), - &Address::random(&fixture.env), - &Address::random(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), + &Address::generate(&fixture.env), ); assert!(result.is_err()); @@ -683,7 +683,7 @@ fn test_pool_config() { ); // Set admin (admin only) - let new_admin = Address::random(&fixture.env); + let new_admin = Address::generate(&fixture.env); pool_fixture.pool.set_admin(&new_admin); assert_eq!( fixture.env.auths()[0], diff --git a/test-suites/tests/test_wasm_happy_path.rs b/test-suites/tests/test_wasm_happy_path.rs index e0a6b250..8897951e 100644 --- a/test-suites/tests/test_wasm_happy_path.rs +++ b/test-suites/tests/test_wasm_happy_path.rs @@ -1,7 +1,7 @@ #![cfg(test)] -use fixed_point_math::FixedPoint; use pool::Request; +use soroban_fixed_point_math::FixedPoint; use soroban_sdk::{testutils::Address as _, vec, Address}; use test_suites::{ assertions::assert_approx_eq_abs, @@ -19,8 +19,8 @@ fn test_wasm_happy_path() { let xlm_pool_index = pool_fixture.reserves[&TokenIndex::XLM]; // Create two new users - let sam = Address::random(&fixture.env); // sam will be supplying XLM and borrowing STABLE - let merry = Address::random(&fixture.env); // merry will be supplying STABLE and borrowing XLM + let sam = Address::generate(&fixture.env); // sam will be supplying XLM and borrowing STABLE + let merry = Address::generate(&fixture.env); // merry will be supplying STABLE and borrowing XLM // Mint users tokens let stable = &fixture.tokens[TokenIndex::STABLE]; @@ -360,13 +360,13 @@ fn test_wasm_happy_path() { 10, ); - // Let one month pass - fixture.jump(60 * 60 * 24 * 30); + // Let rest of emission period pass + fixture.jump(341940); // Distribute emissions fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); - pool_fixture.pool.update_emissions(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); // Frodo claim emissions let mut backstop_blnd_balance = @@ -376,7 +376,7 @@ fn test_wasm_happy_path() { .pool .claim(&frodo, &vec![&fixture.env, 0, 3], &frodo); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 116731656000); + assert_eq!(claim_amount, 11673_1656000); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -385,12 +385,12 @@ fn test_wasm_happy_path() { fixture.tokens[TokenIndex::BLND].balance(&frodo), frodo_balance + claim_amount ); + let claim_amount = fixture.backstop.claim( &frodo, &vec![&fixture.env, pool_fixture.pool.address.clone()], &frodo, ); - assert_eq!(claim_amount, 420798_0000000); backstop_blnd_balance -= claim_amount; assert_eq!( @@ -414,15 +414,16 @@ fn test_wasm_happy_path() { sam_balance + claim_amount ); - // Let a year go by and call update every week - for _ in 0..52 { - // Let one week pass - fixture.jump(60 * 60 * 24 * 7); - // Update emissions - fixture.emitter.distribute(); - fixture.backstop.update_emission_cycle(); - pool_fixture.pool.update_emissions(); - } + // Let 51 weeks go by and call update to validate emissions won't get missed + fixture.jump(60 * 60 * 24 * 7 * 51); + fixture.emitter.distribute(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); + // Allow another week go by to distribute missed emissions + fixture.jump(60 * 60 * 24 * 7); + fixture.emitter.distribute(); + fixture.backstop.gulp_emissions(); + pool_fixture.pool.gulp_emissions(); // Frodo claims a year worth of backstop emissions let mut backstop_blnd_balance = @@ -432,7 +433,7 @@ fn test_wasm_happy_path() { &vec![&fixture.env, pool_fixture.pool.address.clone()], &frodo, ); - assert_eq!(claim_amount, 22014719_9998450); //actual amount is 22014720_0000000 but get's rounded down + assert_eq!(claim_amount, 22014719_9998450); //actual amount is 22014720_0000000 but get's rounded down // 22014719_9998450 backstop_blnd_balance -= 22014719_9998450; assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), @@ -444,7 +445,7 @@ fn test_wasm_happy_path() { .pool .claim(&frodo, &vec![&fixture.env, 0, 3], &frodo); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 1073627_6928000); + assert_eq!(claim_amount, 1073628_1728000); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance @@ -455,7 +456,7 @@ fn test_wasm_happy_path() { .pool .claim(&sam, &vec![&fixture.env, 0, 3], &sam); backstop_blnd_balance -= claim_amount; - assert_eq!(claim_amount, 8361247_4076689); + assert_eq!(claim_amount, 8361251_7312500); assert_eq!( fixture.tokens[TokenIndex::BLND].balance(&fixture.backstop.address), backstop_blnd_balance