diff --git a/Anchor.toml b/Anchor.toml index c3690eaf173..99e41a9b8f5 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -4,6 +4,7 @@ anchor_version = "0.13.2" members = [ "token-lending/program", "token-lending/brick", + "token-lending/wrapper", ] [provider] diff --git a/Cargo.lock b/Cargo.lock index 9d201e66d65..7949f2f6798 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,8 +103,8 @@ checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "regex", "syn 1.0.107", ] @@ -118,8 +118,8 @@ dependencies = [ "anchor-syn", "anyhow", "bs58 0.4.0", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustversion", "syn 1.0.107", ] @@ -131,7 +131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" dependencies = [ "anchor-syn", - "proc-macro2 1.0.49", + "proc-macro2 1.0.66", "syn 1.0.107", ] @@ -142,8 +142,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" dependencies = [ "anchor-syn", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -155,8 +155,8 @@ checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -169,8 +169,8 @@ dependencies = [ "anchor-syn", "anyhow", "heck 0.3.3", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -182,8 +182,8 @@ checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -195,8 +195,8 @@ checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -208,8 +208,8 @@ checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" dependencies = [ "anchor-syn", "anyhow", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -258,9 +258,9 @@ dependencies = [ "anyhow", "bs58 0.3.1", "heck 0.3.3", - "proc-macro2 1.0.49", + "proc-macro2 1.0.66", "proc-macro2-diagnostics", - "quote 1.0.23", + "quote 1.0.33", "serde", "serde_json", "sha2 0.9.9", @@ -332,8 +332,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "synstructure", ] @@ -344,8 +344,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -384,8 +384,8 @@ version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -521,7 +521,7 @@ dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.49", + "proc-macro2 1.0.66", "syn 1.0.107", ] @@ -531,8 +531,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -542,8 +542,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -630,8 +630,8 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -992,8 +992,8 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "scratch", "syn 1.0.107", ] @@ -1010,8 +1010,8 @@ version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -1128,8 +1128,8 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -1210,8 +1210,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0188e3c3ba8df5753894d54461f0e39bc91741dc5b22e1c46999ec2c71f4e4" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -1251,8 +1251,8 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8958699f9359f0b04e691a13850d48b7de329138023876d07cbd024c2c820598" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -1264,8 +1264,8 @@ checksum = "a62bb1df8b45ecb7ffa78dca1c17a438fb193eb083db0b1b494d2a61bcb5096a" dependencies = [ "num-bigint 0.4.3", "num-traits", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustc_version", "syn 1.0.107", ] @@ -1277,8 +1277,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1693044dcf452888dd3a6a6a0dab67f0652094e3920dfe029a54d2f37d9b7394" dependencies = [ "once_cell", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -1407,8 +1407,8 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -2097,8 +2097,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -2185,11 +2185,22 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.33", + "syn 2.0.29", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -2225,9 +2236,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -2258,8 +2269,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate 1.2.1", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -2348,8 +2359,8 @@ checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -2458,8 +2469,8 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -2543,8 +2554,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "version_check", ] @@ -2555,8 +2566,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "version_check", ] @@ -2571,9 +2582,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -2584,8 +2595,8 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "version_check", "yansi", @@ -2633,7 +2644,7 @@ dependencies = [ "borsh", "borsh-derive", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", "pyth-sdk", "serde", @@ -2735,11 +2746,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2 1.0.49", + "proc-macro2 1.0.66", ] [[package]] @@ -2996,7 +3007,7 @@ version = "1.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4903d8db81d2321699ca8318035d6ff805c548868df435813968795a802171b2" dependencies = [ - "quote 1.0.23", + "quote 1.0.33", "rust_decimal", ] @@ -3133,8 +3144,8 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "serde_derive_internals", "syn 1.0.107", ] @@ -3166,8 +3177,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -3234,8 +3245,8 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -3245,8 +3256,8 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -3435,7 +3446,7 @@ dependencies = [ "bincode", "bytemuck", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rustc_version", "serde", @@ -3705,8 +3716,8 @@ version = "1.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c88a0446927b49aee9b40ec1c6a96be562a9de543a0c58483a8520f99f454f36" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustc_version", "syn 1.0.107", ] @@ -3822,7 +3833,7 @@ dependencies = [ "libsecp256k1", "log", "memoffset 0.6.5", - "num-derive", + "num-derive 0.3.3", "num-traits", "parking_lot 0.12.1", "rand 0.7.3", @@ -3858,7 +3869,7 @@ dependencies = [ "libc", "libloading", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rand 0.7.3", "rustc_version", @@ -3915,7 +3926,7 @@ dependencies = [ "console", "dialoguer", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "parking_lot 0.12.1", "qstring", @@ -3950,7 +3961,7 @@ dependencies = [ "log", "lz4", "memmap2", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_cpus", "once_cell", @@ -4012,7 +4023,7 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive", + "num-derive 0.3.3", "num-traits", "pbkdf2 0.11.0", "qstring", @@ -4043,8 +4054,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f511aecadeab3ebc0db10e78d9e7b571dffe1744c0003d6602f537581c3448cf" dependencies = [ "bs58 0.4.0", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustversion", "syn 1.0.107", ] @@ -4072,7 +4083,7 @@ checksum = "2c794a81a68d12192fc08064431b32a0bc9976c7df67c6921fda99604d7bea6e" dependencies = [ "bincode", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rustc_version", "serde", @@ -4169,7 +4180,7 @@ checksum = "ffc47706ca644433d7681f3fe3e0b30094260065ae86a53ae4f92078a7cd4bf4" dependencies = [ "bincode", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rustc_version", "serde", @@ -4190,7 +4201,7 @@ checksum = "d7704396dcd9338e6ac72137908ad5781edd023767d6e6d6b0a68938b8d86fb5" dependencies = [ "bytemuck", "getrandom 0.1.16", - "num-derive", + "num-derive 0.3.3", "num-traits", "solana-program-runtime", "solana-sdk", @@ -4215,7 +4226,7 @@ dependencies = [ "itertools", "lazy_static", "merlin", - "num-derive", + "num-derive 0.3.3", "num-traits", "rand 0.7.3", "serde", @@ -4269,6 +4280,7 @@ dependencies = [ "switchboard-program", "switchboard-v2", "thiserror", + "wrapper", ] [[package]] @@ -4298,7 +4310,7 @@ dependencies = [ "base64 0.13.1", "bytemuck", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "proptest", "pyth-sdk-solana", @@ -4337,7 +4349,7 @@ checksum = "fbc000f0fdf1f12f99d77d398137c1751345b18c88258ce0f99b7872cf6c9bd6" dependencies = [ "assert_matches", "borsh", - "num-derive", + "num-derive 0.3.3", "num-traits", "solana-program", "spl-token", @@ -4362,7 +4374,7 @@ checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum", "solana-program", @@ -4377,7 +4389,7 @@ checksum = "0edb869dbe159b018f17fb9bfa67118c30f232d7f54a73742bc96794dff77ed8" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum", "solana-program", @@ -4421,8 +4433,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.0", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustversion", "syn 1.0.107", ] @@ -4522,8 +4534,19 @@ version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.33", "unicode-ident", ] @@ -4533,8 +4556,8 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "unicode-xid 0.2.4", ] @@ -4580,8 +4603,8 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -4638,8 +4661,8 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -4741,8 +4764,8 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -4863,8 +4886,8 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", ] @@ -5136,8 +5159,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "wasm-bindgen-shared", ] @@ -5160,7 +5183,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ - "quote 1.0.23", + "quote 1.0.33", "wasm-bindgen-macro-support", ] @@ -5170,8 +5193,8 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -5352,6 +5375,29 @@ dependencies = [ "winapi", ] +[[package]] +name = "wrapper" +version = "1.0.1" +dependencies = [ + "assert_matches", + "base64 0.13.1", + "bincode", + "borsh", + "bytemuck", + "log", + "num-derive 0.4.0", + "num-traits", + "proptest", + "serde", + "serde_yaml", + "solana-program", + "solana-program-test", + "solana-sdk", + "solend-sdk", + "spl-token", + "thiserror", +] + [[package]] name = "x509-parser" version = "0.14.0" @@ -5418,8 +5464,8 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ - "proc-macro2 1.0.49", - "quote 1.0.23", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.107", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index a2e7f7ec7cf..18f3d2f01ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,8 @@ members = [ "token-lending/cli", "token-lending/program", "token-lending/sdk", - "token-lending/brick" + "token-lending/brick", + "token-lending/wrapper" ] [profile.dev] diff --git a/token-lending/program/Cargo.toml b/token-lending/program/Cargo.toml index e570407b610..d5c48905125 100644 --- a/token-lending/program/Cargo.toml +++ b/token-lending/program/Cargo.toml @@ -22,6 +22,7 @@ switchboard-v2 = "0.1.3" bytemuck = "1.5.1" [dev-dependencies] +wrapper = { path = "../wrapper" } assert_matches = "1.5.0" bytemuck = "1.5.1" base64 = "0.13" diff --git a/token-lending/program/tests/helpers/solend_program_test.rs b/token-lending/program/tests/helpers/solend_program_test.rs index ed41e80bdad..eb128beba56 100644 --- a/token-lending/program/tests/helpers/solend_program_test.rs +++ b/token-lending/program/tests/helpers/solend_program_test.rs @@ -91,6 +91,12 @@ impl SolendProgramTest { processor!(flash_loan_proxy::process_instruction), ); + test.add_program( + "wrapper", + wrapper::id(), + processor!(wrapper::processor::process_instruction), + ); + let authority = Keypair::new(); add_mint(&mut test, usdc_mint::id(), 6, authority.pubkey()); @@ -141,6 +147,12 @@ impl SolendProgramTest { processor!(flash_loan_proxy::process_instruction), ); + test.add_program( + "wrapper", + wrapper::id(), + processor!(wrapper::processor::process_instruction), + ); + let authority = Keypair::new(); add_mint(&mut test, usdc_mint::id(), 6, authority.pubkey()); diff --git a/token-lending/program/tests/wrapper_program.rs b/token-lending/program/tests/wrapper_program.rs new file mode 100644 index 00000000000..8e90b2dafa6 --- /dev/null +++ b/token-lending/program/tests/wrapper_program.rs @@ -0,0 +1,502 @@ +#![cfg(feature = "test-bpf")] + +use crate::solend_program_test::TokenBalanceChange; +use solana_sdk::instruction::InstructionError; +use solana_sdk::signer::keypair::Keypair; +use solana_sdk::transaction::TransactionError; +use solend_sdk::state::{ReserveFees, ReserveType}; +use std::collections::HashSet; +use wrapper::processor::max_deposit; +use wrapper::processor::max_repay; +use wrapper::processor::withdraw_exact; + +use crate::solend_program_test::custom_scenario; +use crate::solend_program_test::find_reserve; +use crate::solend_program_test::User; + +use crate::solend_program_test::BalanceChecker; +use crate::solend_program_test::ObligationArgs; +use crate::solend_program_test::PriceArgs; +use crate::solend_program_test::ReserveArgs; + +use solana_program::native_token::LAMPORTS_PER_SOL; + +use solana_sdk::signer::Signer; + +use solend_program::state::ReserveConfig; + +mod helpers; + +use helpers::*; +use solana_program_test::*; +use wrapper::processor::liquidate_without_receiving_ctokens; + +#[tokio::test] +async fn test_liquidate() { + let (mut test, lending_market, reserves, obligations, _users, lending_market_owner) = + custom_scenario( + &[ + ReserveArgs { + mint: usdc_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }, + ReserveArgs { + mint: wsol_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 100 * LAMPORTS_PER_SOL, + price: PriceArgs { + price: 10, + conf: 0, + expo: 0, + ema_price: 10, + ema_conf: 0, + }, + }, + ], + &[ + ObligationArgs { + deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)], + borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)], + }, + ObligationArgs { + deposits: vec![(wsol_mint::id(), 100_000 * LAMPORTS_PER_SOL)], + borrows: vec![], + }, + ], + ) + .await; + + test.advance_clock_by_slots(1).await; + + let repay_reserve = find_reserve(&reserves, &wsol_mint::id()).unwrap(); + let withdraw_reserve = find_reserve(&reserves, &usdc_mint::id()).unwrap(); + + lending_market + .update_reserve_config( + &mut test, + &lending_market_owner, + &repay_reserve, + ReserveConfig { + added_borrow_weight_bps: u64::MAX, + ..repay_reserve.account.config + }, + repay_reserve.account.rate_limiter.config, + None, + ) + .await + .unwrap(); + + test.advance_clock_by_slots(1).await; + + let liquidator = User::new_with_balances( + &mut test, + &[ + (&wsol_mint::id(), 100 * LAMPORTS_TO_SOL), + (&withdraw_reserve.account.collateral.mint_pubkey, 0), + (&usdc_mint::id(), 0), + ], + ) + .await; + + let balance_checker = BalanceChecker::start(&mut test, &[&liquidator]).await; + + let mut instructions = lending_market + .build_refresh_instructions(&mut test, &obligations[0], None) + .await; + + instructions.push(liquidate_without_receiving_ctokens( + wrapper::id(), + u64::MAX, + solend_program::id(), + liquidator + .get_account(&repay_reserve.account.liquidity.mint_pubkey) + .unwrap(), + liquidator + .get_account(&withdraw_reserve.account.collateral.mint_pubkey) + .unwrap(), + liquidator + .get_account(&withdraw_reserve.account.liquidity.mint_pubkey) + .unwrap(), + repay_reserve.pubkey, + repay_reserve.account.liquidity.supply_pubkey, + withdraw_reserve.pubkey, + withdraw_reserve.account.collateral.mint_pubkey, + withdraw_reserve.account.collateral.supply_pubkey, + withdraw_reserve.account.liquidity.supply_pubkey, + withdraw_reserve.account.config.fee_receiver, + obligations[0].pubkey, + obligations[0].account.lending_market, + liquidator.keypair.pubkey(), + )); + + test.process_transaction(&instructions, Some(&[&liquidator.keypair])) + .await + .unwrap(); + + let (balance_changes, _) = balance_checker.find_balance_changes(&mut test).await; + let expected_balances_changes = HashSet::from([ + TokenBalanceChange { + token_account: liquidator.get_account(&usdc_mint::id()).unwrap(), + mint: usdc_mint::id(), + diff: (10 * FRACTIONAL_TO_USDC - 1) as i128, + }, + TokenBalanceChange { + token_account: liquidator.get_account(&wsol_mint::id()).unwrap(), + mint: wsol_mint::id(), + diff: -(LAMPORTS_PER_SOL as i128), + }, + ]); + assert_eq!(balance_changes, expected_balances_changes); +} + +#[tokio::test] +async fn test_liquidate_fail() { + let (mut test, lending_market, reserves, obligations, users, lending_market_owner) = + custom_scenario( + &[ + ReserveArgs { + mint: usdc_mint::id(), + config: test_reserve_config(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }, + ReserveArgs { + mint: wsol_mint::id(), + config: test_reserve_config(), + liquidity_amount: 100 * LAMPORTS_PER_SOL, + price: PriceArgs { + price: 10, + conf: 0, + expo: 0, + ema_price: 10, + ema_conf: 0, + }, + }, + ], + &[ + ObligationArgs { + deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)], + borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)], + }, + ObligationArgs { + deposits: vec![(wsol_mint::id(), 100_000 * LAMPORTS_PER_SOL)], + borrows: vec![], + }, + ], + ) + .await; + + test.advance_clock_by_slots(1).await; + + let repay_reserve = find_reserve(&reserves, &wsol_mint::id()).unwrap(); + let withdraw_reserve = find_reserve(&reserves, &usdc_mint::id()).unwrap(); + + lending_market + .update_reserve_config( + &mut test, + &lending_market_owner, + &repay_reserve, + ReserveConfig { + added_borrow_weight_bps: u64::MAX, + ..repay_reserve.account.config + }, + repay_reserve.account.rate_limiter.config, + None, + ) + .await + .unwrap(); + + test.advance_clock_by_slots(1).await; + + lending_market + .borrow_obligation_liquidity( + &mut test, + &withdraw_reserve, + &obligations[1], + &users[1], + None, + u64::MAX, + ) + .await + .unwrap(); + + test.advance_clock_by_slots(1).await; + + let liquidator = User::new_with_balances( + &mut test, + &[ + (&wsol_mint::id(), 100 * LAMPORTS_TO_SOL), + (&withdraw_reserve.account.collateral.mint_pubkey, 0), + (&usdc_mint::id(), 0), + ], + ) + .await; + + let balance_checker = BalanceChecker::start(&mut test, &[&liquidator]).await; + + let mut instructions = lending_market + .build_refresh_instructions(&mut test, &obligations[0], None) + .await; + + instructions.push(liquidate_without_receiving_ctokens( + wrapper::id(), + u64::MAX, + solend_program::id(), + liquidator + .get_account(&repay_reserve.account.liquidity.mint_pubkey) + .unwrap(), + liquidator + .get_account(&withdraw_reserve.account.collateral.mint_pubkey) + .unwrap(), + liquidator + .get_account(&withdraw_reserve.account.liquidity.mint_pubkey) + .unwrap(), + repay_reserve.pubkey, + repay_reserve.account.liquidity.supply_pubkey, + withdraw_reserve.pubkey, + withdraw_reserve.account.collateral.mint_pubkey, + withdraw_reserve.account.collateral.supply_pubkey, + withdraw_reserve.account.liquidity.supply_pubkey, + withdraw_reserve.account.config.fee_receiver, + obligations[0].pubkey, + obligations[0].account.lending_market, + liquidator.keypair.pubkey(), + )); + + let err = test + .process_transaction(&instructions, Some(&[&liquidator.keypair])) + .await + .err() + .unwrap() + .unwrap(); + + assert_eq!( + err, + TransactionError::InstructionError(3, InstructionError::Custom(0)) + ); + let (balance_changes, _) = balance_checker.find_balance_changes(&mut test).await; + assert!(balance_changes.is_empty()); +} + +#[tokio::test] +async fn test_repay() { + let (mut test, lending_market, reserves, obligations, users, _lending_market_owner) = + custom_scenario( + &[ + ReserveArgs { + mint: usdc_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }, + ReserveArgs { + mint: wsol_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 100 * LAMPORTS_PER_SOL, + price: PriceArgs { + price: 10, + conf: 0, + expo: 0, + ema_price: 10, + ema_conf: 0, + }, + }, + ], + &[ObligationArgs { + deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)], + borrows: vec![(wsol_mint::id(), LAMPORTS_PER_SOL)], + }], + ) + .await; + + let instruction = max_repay( + wrapper::id(), + solend_program::id(), + users[0].get_account(&wsol_mint::id()).unwrap(), + reserves[1].account.liquidity.supply_pubkey, + reserves[1].pubkey, + obligations[0].pubkey, + lending_market.pubkey, + users[0].keypair.pubkey(), + ); + + test.process_transaction(&[instruction], Some(&[&users[0].keypair])) + .await + .unwrap(); +} + +#[tokio::test] +async fn test_deposit() { + let (mut test, lending_market, reserves, obligations, users, _lending_market_owner) = + custom_scenario( + &[ReserveArgs { + mint: usdc_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }], + &[ObligationArgs { + deposits: vec![(usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)], + borrows: vec![], + }], + ) + .await; + + test.advance_clock_by_slots(1).await; + + let new_user = + User::new_with_balances(&mut test, &[(&usdc_mint::id(), 100 * FRACTIONAL_TO_USDC)]).await; + + new_user + .transfer( + &usdc_mint::id(), + users[0].get_account(&usdc_mint::id()).unwrap(), + 100 * FRACTIONAL_TO_USDC, + &mut test, + ) + .await; + + test.advance_clock_by_slots(1).await; + + let instruction = max_deposit( + wrapper::id(), + solend_program::id(), + users[0].get_account(&usdc_mint::id()).unwrap(), + users[0] + .get_account(&reserves[0].account.collateral.mint_pubkey) + .unwrap(), + reserves[0].pubkey, + reserves[0].account.liquidity.supply_pubkey, + reserves[0].account.collateral.mint_pubkey, + lending_market.pubkey, + reserves[0].account.collateral.supply_pubkey, + obligations[0].pubkey, + obligations[0].account.owner, + reserves[0].account.liquidity.pyth_oracle_pubkey, + reserves[0].account.liquidity.switchboard_oracle_pubkey, + obligations[0].account.owner, + ); + println!("hello"); + + test.process_transaction(&[instruction], Some(&[&users[0].keypair])) + .await + .unwrap(); +} + +#[tokio::test] +async fn test_withdraw_exact() { + let (mut test, lending_market, reserves, obligations, users, _lending_market_owner) = + custom_scenario( + &[ + ReserveArgs { + mint: usdt_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }, + ReserveArgs { + mint: usdc_mint::id(), + config: reserve_config_no_fees(), + liquidity_amount: 10 * FRACTIONAL_TO_USDC, + price: PriceArgs { + price: 10, + conf: 0, + expo: -1, + ema_price: 10, + ema_conf: 0, + }, + }, + ], + &[ObligationArgs { + deposits: vec![ + (usdc_mint::id(), 100 * FRACTIONAL_TO_USDC), + (usdt_mint::id(), 1 * FRACTIONAL_TO_USDC), + ], + borrows: vec![(usdt_mint::id(), 1 * FRACTIONAL_TO_USDC)], + }], + ) + .await; + + test.advance_clock_by_slots(1).await; + + let balance_checker = BalanceChecker::start(&mut test, &[&users[0]]).await; + + let mut instructions = lending_market + .build_refresh_instructions(&mut test, &obligations[0], None) + .await; + + instructions.push(withdraw_exact( + wrapper::id(), + solend_program::id(), + reserves[0].account.collateral.supply_pubkey, + // user_collateral_pubkey, + users[0] + .get_account(&reserves[0].account.collateral.mint_pubkey) + .unwrap(), + // reserve_pubkey, + reserves[0].pubkey, + // obligation_pubkey, + obligations[0].pubkey, + // lending_market_pubkey, + lending_market.pubkey, + // user_liquidity_pubkey, + users[0] + .get_account(&reserves[0].account.liquidity.mint_pubkey) + .unwrap(), + // reserve_collateral_mint_pubkey, + reserves[0].account.collateral.mint_pubkey, + // reserve_liquidity_supply_pubkey, + reserves[0].account.liquidity.supply_pubkey, + // obligation_owner_pubkey, + obligations[0].account.owner, + // user_transfer_authority_pubkey, + users[0].keypair.pubkey(), + obligations[0] + .account + .deposits + .iter() + .map(|d| d.deposit_reserve) + .collect(), + // liquidity amount + 4 * FRACTIONAL_TO_USDC, + )); + + test.process_transaction(&instructions, Some(&[&users[0].keypair])) + .await + .unwrap(); + + let (balance_changes, _) = balance_checker.find_balance_changes(&mut test).await; + println!("{:?}", balance_changes); +} diff --git a/token-lending/wrapper/Cargo.toml b/token-lending/wrapper/Cargo.toml new file mode 100644 index 00000000000..18a375a52d2 --- /dev/null +++ b/token-lending/wrapper/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "wrapper" +version = "1.0.1" +description = "Solend Wrapper" +authors = ["Solend Maintainers "] +repository = "https://github.com/solendprotocol/solana-program-library" +license = "Apache-2.0" +edition = "2018" + +[features] +no-entrypoint = [] +test-bpf = [] + +[dependencies] +borsh = "0.9.3" +solana-program = "1.14.10" +spl-token = { version = "3.3.0", features=["no-entrypoint"] } +solend-sdk = { path = "../sdk" } +thiserror = "1.0" +num-derive = "0.4.0" +num-traits = "0.2.16" + +[dev-dependencies] +assert_matches = "1.5.0" +bytemuck = "1.5.1" +base64 = "0.13" +log = "0.4.14" +proptest = "1.0" +solana-program-test = "1.14.10" +solana-sdk = "1.14.10" +serde = "=1.0.140" +serde_yaml = "0.8" +thiserror = "1.0" +bincode = "1.3.3" +borsh = "0.9.3" + +[lib] +crate-type = ["cdylib", "lib"] + +[profile.release] +lto = "fat" +codegen-units = 1 + +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/token-lending/wrapper/Xargo.toml b/token-lending/wrapper/Xargo.toml new file mode 100644 index 00000000000..1744f098ae1 --- /dev/null +++ b/token-lending/wrapper/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/token-lending/wrapper/src/entrypoint.rs b/token-lending/wrapper/src/entrypoint.rs new file mode 100644 index 00000000000..48e3027b9d0 --- /dev/null +++ b/token-lending/wrapper/src/entrypoint.rs @@ -0,0 +1,17 @@ +//! Program entrypoint definitions + +#![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))] + +use crate::processor; +use solana_program::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + processor::process_instruction(program_id, accounts, instruction_data) +} diff --git a/token-lending/wrapper/src/lib.rs b/token-lending/wrapper/src/lib.rs new file mode 100644 index 00000000000..de3683e9e79 --- /dev/null +++ b/token-lending/wrapper/src/lib.rs @@ -0,0 +1,10 @@ +#![deny(missing_docs)] + +//! A brick. + +pub use solana_program; + +solana_program::declare_id!("2eEso2sAipRHNZ54d4fRJyeC6mVJq73F5mvsL1wZb3tp"); + +pub mod entrypoint; +pub mod processor; diff --git a/token-lending/wrapper/src/processor.rs b/token-lending/wrapper/src/processor.rs new file mode 100644 index 00000000000..e2bfce2ebc4 --- /dev/null +++ b/token-lending/wrapper/src/processor.rs @@ -0,0 +1,517 @@ +//! Program state processor + +use borsh::{BorshDeserialize, BorshSerialize}; +use num_derive::FromPrimitive; +use solana_program::pubkey::PUBKEY_BYTES; +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + instruction::{AccountMeta, Instruction}, + msg, + program::invoke, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, +}; +use solend_sdk::instruction::{ + deposit_reserve_liquidity_and_obligation_collateral, + liquidate_obligation_and_redeem_reserve_collateral, repay_obligation_liquidity, + withdraw_obligation_collateral_and_redeem_reserve_collateral, +}; +use solend_sdk::math::Decimal; +use solend_sdk::math::TrySub; +use solend_sdk::state::Reserve; +use thiserror::Error; + +/// Instruction types +#[derive(BorshSerialize, BorshDeserialize)] +pub enum WrapperInstruction { + /// Accounts: + /// 0: PriceAccount (uninitialized) + /// 1: ProductAccount (uninitialized) + LiquidateWithoutReceivingCtokens { + /// amount to liquidate + liquidity_amount: u64, + }, + /// Repay obligation liquidity with max amount in token account + RepayMax, + /// Deposit max + DepositMax, + /// Withdraw exact + WithdrawExact { + /// Exact amount to withdraw + liquidity_amount: u64, + }, +} + +/// Processes an instruction +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + input: &[u8], +) -> ProgramResult { + let instruction = WrapperInstruction::try_from_slice(input)?; + match instruction { + WrapperInstruction::LiquidateWithoutReceivingCtokens { liquidity_amount } => { + msg!("Instruction: LiquidateWithoutReceivingCtokens"); + let account_info_iter = &mut accounts.iter(); + let solend_program_info = next_account_info(account_info_iter)?; + let source_liquidity_info = next_account_info(account_info_iter)?; + let destination_collateral_info = next_account_info(account_info_iter)?; + let destination_liquidity_info = next_account_info(account_info_iter)?; + let repay_reserve_info = next_account_info(account_info_iter)?; + let repay_reserve_liquidity_supply_info = next_account_info(account_info_iter)?; + let withdraw_reserve_info = next_account_info(account_info_iter)?; + let withdraw_reserve_collateral_mint_info = next_account_info(account_info_iter)?; + let withdraw_reserve_collateral_supply_info = next_account_info(account_info_iter)?; + let withdraw_reserve_liquidity_supply_info = next_account_info(account_info_iter)?; + let withdraw_reserve_liquidity_fee_receiver_info = + next_account_info(account_info_iter)?; + let obligation_info = next_account_info(account_info_iter)?; + let lending_market_info = next_account_info(account_info_iter)?; + let lending_market_authority_info = next_account_info(account_info_iter)?; + let user_transfer_authority_info = next_account_info(account_info_iter)?; + let token_program_id = next_account_info(account_info_iter)?; + + let instruction = liquidate_obligation_and_redeem_reserve_collateral( + *solend_program_info.key, + liquidity_amount, + *source_liquidity_info.key, + *destination_collateral_info.key, + *destination_liquidity_info.key, + *repay_reserve_info.key, + *repay_reserve_liquidity_supply_info.key, + *withdraw_reserve_info.key, + *withdraw_reserve_collateral_mint_info.key, + *withdraw_reserve_collateral_supply_info.key, + *withdraw_reserve_liquidity_supply_info.key, + *withdraw_reserve_liquidity_fee_receiver_info.key, + *obligation_info.key, + *lending_market_info.key, + *user_transfer_authority_info.key, + ); + + let account_infos = [ + solend_program_info.clone(), + source_liquidity_info.clone(), + destination_collateral_info.clone(), + destination_liquidity_info.clone(), + repay_reserve_info.clone(), + repay_reserve_liquidity_supply_info.clone(), + withdraw_reserve_info.clone(), + withdraw_reserve_collateral_mint_info.clone(), + withdraw_reserve_collateral_supply_info.clone(), + withdraw_reserve_liquidity_supply_info.clone(), + withdraw_reserve_liquidity_fee_receiver_info.clone(), + obligation_info.clone(), + lending_market_info.clone(), + lending_market_authority_info.clone(), + user_transfer_authority_info.clone(), + token_program_id.clone(), + ]; + + let ctoken_balance_before = spl_token::state::Account::unpack_from_slice( + &destination_collateral_info.try_borrow_data()?, + )? + .amount; + + invoke(&instruction, &account_infos)?; + + let ctoken_balance_after = spl_token::state::Account::unpack_from_slice( + &destination_collateral_info.try_borrow_data()?, + )? + .amount; + + if ctoken_balance_after > ctoken_balance_before { + msg!("We received ctokens, aborting"); + return Err(WrapperError::ReceivedCTokens.into()); + } + + Ok(()) + } + WrapperInstruction::RepayMax => { + msg!("Instruction: RepayMax"); + let account_info_iter = &mut accounts.iter(); + let solend_program_id = next_account_info(account_info_iter)?; + let source_liquidity_info = next_account_info(account_info_iter)?; + let destination_liquidity_info = next_account_info(account_info_iter)?; + let repay_reserve_info = next_account_info(account_info_iter)?; + let obligation_info = next_account_info(account_info_iter)?; + let lending_market_info = next_account_info(account_info_iter)?; + let user_transfer_authority_info = next_account_info(account_info_iter)?; + let token_program_id = next_account_info(account_info_iter)?; + + let source_liquidity_balance = spl_token::state::Account::unpack_from_slice( + &source_liquidity_info.try_borrow_data()?, + )? + .amount; + msg!("source_liquidity_balance: {}", source_liquidity_balance); + + let instruction = repay_obligation_liquidity( + *solend_program_id.key, + source_liquidity_balance, + *source_liquidity_info.key, + *destination_liquidity_info.key, + *repay_reserve_info.key, + *obligation_info.key, + *lending_market_info.key, + *user_transfer_authority_info.key, + ); + + invoke( + &instruction, + &[ + solend_program_id.clone(), + source_liquidity_info.clone(), + destination_liquidity_info.clone(), + repay_reserve_info.clone(), + obligation_info.clone(), + lending_market_info.clone(), + user_transfer_authority_info.clone(), + token_program_id.clone(), + ], + )?; + + Ok(()) + } + WrapperInstruction::DepositMax => { + msg!("Instruction: DepositMax"); + let account_info_iter = &mut accounts.iter(); + let solend_program_id = next_account_info(account_info_iter)?; + let source_liquidity_info = next_account_info(account_info_iter)?; + let user_collateral_info = next_account_info(account_info_iter)?; + let reserve_info = next_account_info(account_info_iter)?; + let reserve_liquidity_supply_info = next_account_info(account_info_iter)?; + let reserve_collateral_mint_info = next_account_info(account_info_iter)?; + let lending_market_info = next_account_info(account_info_iter)?; + let lending_market_authority_info = next_account_info(account_info_iter)?; + let destination_collateral_info = next_account_info(account_info_iter)?; + let obligation_info = next_account_info(account_info_iter)?; + let obligation_owner_info = next_account_info(account_info_iter)?; + let pyth_price_info = next_account_info(account_info_iter)?; + let switchboard_feed_info = next_account_info(account_info_iter)?; + let user_transfer_authority_info = next_account_info(account_info_iter)?; + let token_program_id = next_account_info(account_info_iter)?; + + let source_liquidity_balance = spl_token::state::Account::unpack_from_slice( + &source_liquidity_info.try_borrow_data()?, + )? + .amount; + + let reserve = Reserve::unpack(&reserve_info.try_borrow_data()?)?; + let remaining_deposit_capacity = Decimal::from(reserve.config.deposit_limit) + .try_sub(reserve.liquidity.total_supply()?)?; + let source_liquidity_balance = std::cmp::min( + source_liquidity_balance, + remaining_deposit_capacity.try_floor_u64()?, + ); + + msg!("source_liquidity_balance: {}", source_liquidity_balance); + let instruction = deposit_reserve_liquidity_and_obligation_collateral( + *solend_program_id.key, + source_liquidity_balance, + *source_liquidity_info.key, + *user_collateral_info.key, + *reserve_info.key, + *reserve_liquidity_supply_info.key, + *reserve_collateral_mint_info.key, + *lending_market_info.key, + *destination_collateral_info.key, + *obligation_info.key, + *obligation_owner_info.key, + *pyth_price_info.key, + *switchboard_feed_info.key, + *user_transfer_authority_info.key, + ); + invoke( + &instruction, + &[ + solend_program_id.clone(), + source_liquidity_info.clone(), + user_collateral_info.clone(), + reserve_info.clone(), + reserve_liquidity_supply_info.clone(), + reserve_collateral_mint_info.clone(), + lending_market_info.clone(), + lending_market_authority_info.clone(), + destination_collateral_info.clone(), + obligation_info.clone(), + obligation_owner_info.clone(), + pyth_price_info.clone(), + switchboard_feed_info.clone(), + user_transfer_authority_info.clone(), + token_program_id.clone(), + ], + )?; + + Ok(()) + } + WrapperInstruction::WithdrawExact { liquidity_amount } => { + msg!("Instruction: WithdrawExact"); + + let account_info_iter = &mut accounts.iter(); + let solend_program_id = next_account_info(account_info_iter)?; + let reserve_collateral_info = next_account_info(account_info_iter)?; + let user_collateral_info = next_account_info(account_info_iter)?; + let reserve_info = next_account_info(account_info_iter)?; + let obligation_info = next_account_info(account_info_iter)?; + let lending_market_info = next_account_info(account_info_iter)?; + let lending_market_authority_info = next_account_info(account_info_iter)?; + let user_liquidity_info = next_account_info(account_info_iter)?; + let reserve_collateral_mint_info = next_account_info(account_info_iter)?; + let reserve_liquidity_supply_info = next_account_info(account_info_iter)?; + let obligation_owner_info = next_account_info(account_info_iter)?; + let user_transfer_authority_info = next_account_info(account_info_iter)?; + let token_program_id = next_account_info(account_info_iter)?; + + // while account info iter has pubkeys, add them to collateral reserves + let collateral_reserves: Vec<_> = account_info_iter.cloned().collect(); + + let reserve = Reserve::unpack(&reserve_info.try_borrow_data()?)?; + let mut ctoken_amount = reserve + .collateral_exchange_rate()? + .liquidity_to_collateral(liquidity_amount)?; + + let liquidity_out = reserve + .collateral_exchange_rate()? + .collateral_to_liquidity(ctoken_amount)?; + if liquidity_out < liquidity_amount { + ctoken_amount += 1; + } + + let instruction = withdraw_obligation_collateral_and_redeem_reserve_collateral( + *solend_program_id.key, + ctoken_amount, + *reserve_collateral_info.key, + *user_collateral_info.key, + *reserve_info.key, + *obligation_info.key, + *lending_market_info.key, + *user_liquidity_info.key, + *reserve_collateral_mint_info.key, + *reserve_liquidity_supply_info.key, + *obligation_owner_info.key, + *user_transfer_authority_info.key, + collateral_reserves + .iter() + .map(|account_info| *account_info.key) + .collect(), + ); + + invoke(&instruction, &{ + let mut accounts = vec![ + solend_program_id.clone(), + reserve_collateral_info.clone(), + user_collateral_info.clone(), + reserve_info.clone(), + obligation_info.clone(), + lending_market_info.clone(), + lending_market_authority_info.clone(), + user_liquidity_info.clone(), + reserve_collateral_mint_info.clone(), + reserve_liquidity_supply_info.clone(), + obligation_owner_info.clone(), + user_transfer_authority_info.clone(), + token_program_id.clone(), + ]; + accounts.extend(collateral_reserves); + + accounts + })?; + + Ok(()) + } + } +} + +/// Errors that may be returned by the TokenLending program. +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum WrapperError { + /// Received ctokens + #[error("Received ctokens")] + ReceivedCTokens, +} + +impl From for ProgramError { + fn from(e: WrapperError) -> Self { + ProgramError::Custom(e as u32) + } +} + +/// Creates a `LiquidateObligationAndRedeemReserveCollateral` instruction +#[allow(clippy::too_many_arguments)] +pub fn liquidate_without_receiving_ctokens( + program_id: Pubkey, + liquidity_amount: u64, + solend_program_id: Pubkey, + source_liquidity_pubkey: Pubkey, + destination_collateral_pubkey: Pubkey, + destination_liquidity_pubkey: Pubkey, + repay_reserve_pubkey: Pubkey, + repay_reserve_liquidity_supply_pubkey: Pubkey, + withdraw_reserve_pubkey: Pubkey, + withdraw_reserve_collateral_mint_pubkey: Pubkey, + withdraw_reserve_collateral_supply_pubkey: Pubkey, + withdraw_reserve_liquidity_supply_pubkey: Pubkey, + withdraw_reserve_liquidity_fee_receiver_pubkey: Pubkey, + obligation_pubkey: Pubkey, + lending_market_pubkey: Pubkey, + user_transfer_authority_pubkey: Pubkey, +) -> Instruction { + let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address( + &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]], + &solend_program_id, + ); + Instruction { + program_id, + accounts: vec![ + AccountMeta::new_readonly(solend_program_id, false), + AccountMeta::new(source_liquidity_pubkey, false), + AccountMeta::new(destination_collateral_pubkey, false), + AccountMeta::new(destination_liquidity_pubkey, false), + AccountMeta::new(repay_reserve_pubkey, false), + AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false), + AccountMeta::new(withdraw_reserve_pubkey, false), + AccountMeta::new(withdraw_reserve_collateral_mint_pubkey, false), + AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false), + AccountMeta::new(withdraw_reserve_liquidity_supply_pubkey, false), + AccountMeta::new(withdraw_reserve_liquidity_fee_receiver_pubkey, false), + AccountMeta::new(obligation_pubkey, false), + AccountMeta::new(lending_market_pubkey, false), + AccountMeta::new_readonly(lending_market_authority_pubkey, false), + AccountMeta::new_readonly(user_transfer_authority_pubkey, true), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: WrapperInstruction::LiquidateWithoutReceivingCtokens { liquidity_amount } + .try_to_vec() + .unwrap(), + } +} + +/// max repay instruction +#[allow(clippy::too_many_arguments)] +pub fn max_repay( + program_id: Pubkey, + solend_program_id: Pubkey, + source_liquidity_pubkey: Pubkey, + destination_liquidity_pubkey: Pubkey, + repay_reserve_pubkey: Pubkey, + obligation_pubkey: Pubkey, + lending_market_pubkey: Pubkey, + user_transfer_authority_pubkey: Pubkey, +) -> Instruction { + Instruction { + program_id, + accounts: vec![ + AccountMeta::new_readonly(solend_program_id, false), + AccountMeta::new(source_liquidity_pubkey, false), + AccountMeta::new(destination_liquidity_pubkey, false), + AccountMeta::new(repay_reserve_pubkey, false), + AccountMeta::new(obligation_pubkey, false), + AccountMeta::new(lending_market_pubkey, false), + AccountMeta::new_readonly(user_transfer_authority_pubkey, true), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: WrapperInstruction::RepayMax.try_to_vec().unwrap(), + } +} + +/// max deposit +#[allow(clippy::too_many_arguments)] +pub fn max_deposit( + program_id: Pubkey, + solend_program_id: Pubkey, + source_liquidity_pubkey: Pubkey, + user_collateral_pubkey: Pubkey, + reserve_pubkey: Pubkey, + reserve_liquidity_supply_pubkey: Pubkey, + reserve_collateral_mint_pubkey: Pubkey, + lending_market_pubkey: Pubkey, + destination_deposit_collateral_pubkey: Pubkey, + obligation_pubkey: Pubkey, + obligation_owner_pubkey: Pubkey, + reserve_liquidity_pyth_oracle_pubkey: Pubkey, + reserve_liquidity_switchboard_oracle_pubkey: Pubkey, + user_transfer_authority_pubkey: Pubkey, +) -> Instruction { + let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address( + &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]], + &solend_program_id, + ); + + Instruction { + program_id, + accounts: vec![ + AccountMeta::new_readonly(solend_program_id, false), + AccountMeta::new(source_liquidity_pubkey, false), + AccountMeta::new(user_collateral_pubkey, false), + AccountMeta::new(reserve_pubkey, false), + AccountMeta::new(reserve_liquidity_supply_pubkey, false), + AccountMeta::new(reserve_collateral_mint_pubkey, false), + AccountMeta::new_readonly(lending_market_pubkey, false), + AccountMeta::new_readonly(lending_market_authority_pubkey, false), + AccountMeta::new(destination_deposit_collateral_pubkey, false), + AccountMeta::new(obligation_pubkey, false), + AccountMeta::new(obligation_owner_pubkey, true), + AccountMeta::new_readonly(reserve_liquidity_pyth_oracle_pubkey, false), + AccountMeta::new_readonly(reserve_liquidity_switchboard_oracle_pubkey, false), + AccountMeta::new_readonly(user_transfer_authority_pubkey, true), + AccountMeta::new_readonly(spl_token::id(), false), + ], + data: WrapperInstruction::DepositMax.try_to_vec().unwrap(), + } +} + +/// withdraw exact +#[allow(clippy::too_many_arguments)] +pub fn withdraw_exact( + program_id: Pubkey, + solend_program_id: Pubkey, + reserve_collateral_pubkey: Pubkey, + user_collateral_pubkey: Pubkey, + reserve_pubkey: Pubkey, + obligation_pubkey: Pubkey, + lending_market_pubkey: Pubkey, + user_liquidity_pubkey: Pubkey, + reserve_collateral_mint_pubkey: Pubkey, + reserve_liquidity_supply_pubkey: Pubkey, + obligation_owner_pubkey: Pubkey, + user_transfer_authority_pubkey: Pubkey, + collateral_reserves: Vec, + liquidity_amount: u64, +) -> Instruction { + let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address( + &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]], + &solend_program_id, + ); + + let mut accounts = vec![ + AccountMeta::new_readonly(solend_program_id, false), + AccountMeta::new(reserve_collateral_pubkey, false), + AccountMeta::new(user_collateral_pubkey, false), + AccountMeta::new(reserve_pubkey, false), + AccountMeta::new(obligation_pubkey, false), + AccountMeta::new(lending_market_pubkey, false), + AccountMeta::new_readonly(lending_market_authority_pubkey, false), + AccountMeta::new(user_liquidity_pubkey, false), + AccountMeta::new(reserve_collateral_mint_pubkey, false), + AccountMeta::new(reserve_liquidity_supply_pubkey, false), + AccountMeta::new(obligation_owner_pubkey, true), + AccountMeta::new_readonly(user_transfer_authority_pubkey, true), + AccountMeta::new_readonly(spl_token::id(), false), + ]; + + accounts.extend( + collateral_reserves + .iter() + .map(|reserve| AccountMeta::new(*reserve, false)), + ); + + Instruction { + program_id, + accounts, + data: WrapperInstruction::WithdrawExact { liquidity_amount } + .try_to_vec() + .unwrap(), + } +}