diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index fea50219b..e3d938363 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -152,6 +152,7 @@ jobs: - tests/voter-stake-registry.ts - tests/fanout.ts - tests/sus.ts + - tests/conversion-escrow.ts - tests/position-voting-rewards.ts steps: - uses: actions/checkout@v3 diff --git a/Anchor.toml b/Anchor.toml index bbf70be50..7de0a709d 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -17,6 +17,7 @@ fanout = "fanqeMu3fw8R4LwKNbahPtYXJsyLL6NXyfe2BqzhfB6" mobile_entity_manager = "memMa1HG4odAFmUbGWfPwS1WWfK95k99F2YTkGvyxZr" hexboosting = "hexbnKYoA2GercNNhHUCCfrTRWrHjT6ujKPXTa5NPqJ" no_emit = "noEmmgLmQdk6DLiPV8CSwQv3qQDyGEhz9m5A4zhtByv" +conversion_escrow = "cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w" position_voting_rewards = "pvr1pJdeAcW6tzFyPRSmkL5Xwysi1Tq79f7KF2XB4zM" [workspace] @@ -35,6 +36,7 @@ members = [ "programs/mobile-entity-manager", "programs/hexboosting", "programs/no-emit", + "programs/conversion-escrow", "programs/position-voting-rewards", ] @@ -103,6 +105,18 @@ address = "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx" # Mobile price oracle [[test.validator.clone]] address = "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33" +# Helium Common LUT +[[test.validator.clone]] +address = "43eY9L2spbM2b1MPDFFBStUiFGt29ziZ1nc1xbpzsfVt" + +# Sol pyth price +[[test.validator.clone]] +address = "7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE" + +# Pyth usdc price oracle +[[test.validator.clone]] +address = "Dpw1EAVrSB1ibxiDQyTAW6Zip3J4Btk2x4SgApQCeFbX" + # Squads multisig program [[test.validator.clone]] address = "SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu" diff --git a/Cargo.lock b/Cargo.lock index 88bc474ef..3095e1b4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ dependencies = [ "anchor-syn 0.28.0", "anyhow", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "regex", "syn 1.0.109", ] @@ -150,7 +150,7 @@ dependencies = [ "anyhow", "bs58 0.5.0", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "rustversion", "syn 1.0.109", ] @@ -174,7 +174,7 @@ checksum = "fc753c9d1c7981cb8948cf7e162fb0f64558999c0413058e2d43df1df5448086" dependencies = [ "anchor-syn 0.28.0", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -187,7 +187,7 @@ dependencies = [ "anchor-syn 0.28.0", "anyhow", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -200,7 +200,7 @@ dependencies = [ "anchor-syn 0.28.0", "anyhow", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -213,7 +213,7 @@ dependencies = [ "anchor-syn 0.28.0", "anyhow", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -224,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f495e85480bd96ddeb77b71d499247c7d4e8b501e75ecb234e9ef7ae7bd6552a" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -265,7 +265,7 @@ dependencies = [ "darling 0.14.4", "heck 0.4.1", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "serde_json", "syn 1.0.109", ] @@ -318,7 +318,7 @@ dependencies = [ "heck 0.3.3", "proc-macro2 1.0.79", "proc-macro2-diagnostics", - "quote 1.0.33", + "quote 1.0.36", "serde", "serde_json", "sha2 0.9.9", @@ -336,7 +336,7 @@ dependencies = [ "bs58 0.5.0", "heck 0.3.3", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "serde", "serde_json", "sha2 0.10.7", @@ -437,7 +437,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -450,7 +450,7 @@ dependencies = [ "num-bigint 0.4.4", "num-traits", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -486,7 +486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -547,7 +547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", "synstructure", ] @@ -559,7 +559,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -610,8 +610,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -792,7 +792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -803,7 +803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -814,7 +814,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -825,7 +825,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -913,8 +913,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1127,6 +1127,19 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "conversion-escrow" +version = "0.0.1" +dependencies = [ + "anchor-lang", + "anchor-spl", + "default-env", + "pyth-solana-receiver-sdk", + "shared-utils", + "solana-security-txt", + "spl-token", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1282,7 +1295,7 @@ dependencies = [ "fnv", "ident_case", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "strsim 0.10.0", "syn 1.0.109", ] @@ -1296,9 +1309,9 @@ dependencies = [ "fnv", "ident_case", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "strsim 0.10.0", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -1308,7 +1321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core 0.14.4", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -1319,8 +1332,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1410,7 +1423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -1462,8 +1475,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1489,6 +1502,12 @@ dependencies = [ "syn 0.15.44", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "eager" version = "0.1.0" @@ -1538,7 +1557,7 @@ checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" dependencies = [ "enum-ordinalize", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -1579,8 +1598,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1592,8 +1611,8 @@ dependencies = [ "num-bigint 0.4.4", "num-traits", "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1767,8 +1786,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -1952,11 +1971,14 @@ dependencies = [ "bs58 0.3.1", "bubblegum-cpi", "bytemuck", + "circuit-breaker", + "conversion-escrow", "data-credits", "default-env", "helium-sub-daos", "mpl-token-metadata", "no-emit", + "pyth-sdk-solana", "pyth-solana-receiver-sdk", "shared-utils", "solana-security-txt", @@ -2563,7 +2585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -2682,7 +2704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -2764,7 +2786,7 @@ checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -2776,8 +2798,8 @@ checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -2866,7 +2888,7 @@ dependencies = [ "Inflector", "proc-macro-error", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -2957,8 +2979,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -3075,7 +3097,7 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", "version_check", ] @@ -3087,7 +3109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "version_check", ] @@ -3116,7 +3138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", "version_check", "yansi", @@ -3130,6 +3152,37 @@ dependencies = [ "anchor-lang", ] +[[package]] +name = "pyth-sdk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7aeef4d5f0a9c98ff5af2ddd84a8b89919c512188305b497a9eb9afa97a949" +dependencies = [ + "borsh 0.10.3", + "borsh-derive 0.10.3", + "getrandom 0.2.10", + "hex", + "schemars", + "serde", +] + +[[package]] +name = "pyth-sdk-solana" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa571ea6ea51102b8fc03303d0e6fea4f788f77bb4e0d65ae2d3c5e384e3187" +dependencies = [ + "borsh 0.10.3", + "borsh-derive 0.10.3", + "bytemuck", + "num-derive", + "num-traits", + "pyth-sdk", + "serde", + "solana-program", + "thiserror", +] + [[package]] name = "pyth-solana-receiver-sdk" version = "0.3.0" @@ -3234,9 +3287,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2 1.0.79", ] @@ -3620,6 +3673,30 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "serde_derive_internals", + "syn 2.0.58", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -3642,8 +3719,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -3710,8 +3787,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -3755,8 +3843,8 @@ checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ "darling 0.20.3", "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -4176,9 +4264,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db08ab0af4007dc0954b900aa5febc0c0ae50d9f9f598be27263c3195d90240b" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "rustc_version", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -4662,9 +4750,9 @@ checksum = "a75b33716470fa4a65a23ddc2d4abcb8d28532c6e3ae3f04f4fe79b5e1f8c247" dependencies = [ "bs58 0.4.0", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "rustversion", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -5053,7 +5141,7 @@ checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "rustversion", "syn 1.0.109", ] @@ -5088,18 +5176,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.37" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "unicode-ident", ] @@ -5110,7 +5198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", "unicode-xid 0.2.4", ] @@ -5157,7 +5245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", + "quote 1.0.36", "syn 1.0.109", ] @@ -5214,8 +5302,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -5319,8 +5407,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -5468,8 +5556,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] @@ -5765,8 +5853,8 @@ dependencies = [ "log", "once_cell", "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -5788,7 +5876,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote 1.0.33", + "quote 1.0.36", "wasm-bindgen-macro-support", ] @@ -5799,8 +5887,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6110,8 +6198,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.79", - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.36", + "syn 2.0.58", ] [[package]] diff --git a/packages/anchor-resolvers/src/heliumCommonResolver.ts b/packages/anchor-resolvers/src/heliumCommonResolver.ts index 915ae31ce..6c24ec294 100644 --- a/packages/anchor-resolvers/src/heliumCommonResolver.ts +++ b/packages/anchor-resolvers/src/heliumCommonResolver.ts @@ -4,6 +4,10 @@ import { resolveIndividual } from "./individual"; export const heliumCommonResolver = resolveIndividual(async ({ path }) => { switch (path[path.length - 1]) { + case "conversionEscrowProgram": + return new PublicKey("cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w"); + case "circuitBreakerProgram": + return new PublicKey("circAbx64bbsscPbQzZAUvuXpHqrCe6fLMzc2uKXz9g"); case "dataCreditsProgram": return new PublicKey("credMBJhYFzfn7NxBMdU4aUqFggAjgztaCcv2Fo6fPT"); case "tokenMetadataProgram": diff --git a/packages/conversion-escrow-sdk/.gitignore b/packages/conversion-escrow-sdk/.gitignore new file mode 100644 index 000000000..445f244bc --- /dev/null +++ b/packages/conversion-escrow-sdk/.gitignore @@ -0,0 +1,4 @@ +npm-debug.log +dist/ +tmp/ +./node_modules \ No newline at end of file diff --git a/packages/conversion-escrow-sdk/CHANGELOG.md b/packages/conversion-escrow-sdk/CHANGELOG.md new file mode 100644 index 000000000..ee59f464c --- /dev/null +++ b/packages/conversion-escrow-sdk/CHANGELOG.md @@ -0,0 +1,160 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.6.41](https://github.com/helium/helium-program-libary/compare/v0.6.40...v0.6.41) (2024-03-18) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.40](https://github.com/helium/helium-program-libary/compare/v0.6.39...v0.6.40) (2024-03-18) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.39](https://github.com/helium/helium-program-libary/compare/v0.6.38...v0.6.39) (2024-03-13) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.38](https://github.com/helium/helium-program-libary/compare/v0.6.37...v0.6.38) (2024-03-11) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.37](https://github.com/helium/helium-program-libary/compare/v0.6.35...v0.6.37) (2024-03-11) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.36](https://github.com/helium/helium-program-libary/compare/v0.6.27...v0.6.36) (2024-03-08) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.35](https://github.com/helium/helium-program-libary/compare/v0.6.34...v0.6.35) (2024-03-04) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.34](https://github.com/helium/helium-program-libary/compare/v0.6.33...v0.6.34) (2024-03-04) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.33](https://github.com/helium/helium-program-libary/compare/v0.6.32...v0.6.33) (2024-03-01) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.32](https://github.com/helium/helium-program-libary/compare/v0.6.31...v0.6.32) (2024-02-28) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.31](https://github.com/helium/helium-program-libary/compare/v0.6.30...v0.6.31) (2024-02-28) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.30](https://github.com/helium/helium-program-libary/compare/v0.6.29...v0.6.30) (2024-02-22) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.29](https://github.com/helium/helium-program-libary/compare/v0.6.28...v0.6.29) (2024-02-06) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.28](https://github.com/helium/helium-program-libary/compare/v0.6.27...v0.6.28) (2024-02-06) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.27](https://github.com/helium/helium-program-libary/compare/v0.6.25...v0.6.27) (2024-02-01) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.26](https://github.com/helium/helium-program-libary/compare/v0.6.5...v0.6.26) (2024-01-31) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.25](https://github.com/helium/helium-program-libary/compare/v0.6.24...v0.6.25) (2024-01-29) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.24](https://github.com/helium/helium-program-libary/compare/v0.6.23...v0.6.24) (2024-01-29) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.23](https://github.com/helium/helium-program-libary/compare/v0.6.20...v0.6.23) (2024-01-20) + +**Note:** Version bump only for package @helium/hexboosting-sdk + + + + + +## [0.6.22](https://github.com/helium/helium-program-libary/compare/v0.6.5...v0.6.22) (2024-01-19) + +**Note:** Version bump only for package @helium/hexboosting-sdk diff --git a/packages/conversion-escrow-sdk/package.json b/packages/conversion-escrow-sdk/package.json new file mode 100644 index 000000000..de027e64c --- /dev/null +++ b/packages/conversion-escrow-sdk/package.json @@ -0,0 +1,49 @@ +{ + "name": "@helium/conversion-escrow-sdk", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "license": "Apache-2.0", + "version": "0.6.42", + "description": "Interface to the conversion-escrow smart contract", + "repository": { + "type": "git", + "url": "https://github.com/helium/helium-program-libary" + }, + "main": "./lib/cjs/index.js", + "module": "./lib/esm/src/index.js", + "types": "./lib/types/src/index.d.ts", + "sideEffects": false, + "files": [ + "lib" + ], + "exports": { + "import": "./lib/esm/src/index.js", + "require": "./lib/cjs/index.js", + "types": "./lib/types/src/index.d.ts" + }, + "scripts": { + "format": "prettier --write \"src/**/*.{ts,tsx}\"", + "precommit": "npx git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' .", + "clean": "npx shx mkdir -p lib && npx shx rm -rf lib", + "package": "npx shx mkdir -p lib/cjs lib/esm", + "prebuild": "npm run clean && npm run package" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.28.0", + "@helium/anchor-resolvers": "^0.6.42", + "@helium/idls": "^0.6.42", + "bn.js": "^5.2.0", + "bs58": "^4.0.1" + }, + "devDependencies": { + "git-format-staged": "^2.1.3", + "ts-loader": "^9.2.3", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + }, + "keywords": [], + "author": "", + "gitHead": "5a8bf0b7b88e5934ef8d774e686f7c95804fbb8d" +} diff --git a/packages/conversion-escrow-sdk/src/constants.ts b/packages/conversion-escrow-sdk/src/constants.ts new file mode 100644 index 000000000..140f72ed3 --- /dev/null +++ b/packages/conversion-escrow-sdk/src/constants.ts @@ -0,0 +1,3 @@ +import { PublicKey } from "@solana/web3.js"; + +export const PROGRAM_ID = new PublicKey("cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w"); diff --git a/packages/conversion-escrow-sdk/src/index.ts b/packages/conversion-escrow-sdk/src/index.ts new file mode 100644 index 000000000..c0e3c10a1 --- /dev/null +++ b/packages/conversion-escrow-sdk/src/index.ts @@ -0,0 +1,29 @@ +import { ConversionEscrow } from "@helium/idls/lib/types/conversion_escrow"; +import { AnchorProvider, Idl, Program } from "@coral-xyz/anchor"; +import { PublicKey } from "@solana/web3.js"; +import { PROGRAM_ID } from "./constants"; +import { conversionEscrowResolvers } from "./resolvers"; + + +export * from "./constants"; +export * from "./pdas"; + +export async function init( + provider: AnchorProvider, + programId: PublicKey = PROGRAM_ID, + idl?: Idl | null +): Promise> { + if (!idl) { + idl = await Program.fetchIdl(programId, provider); + } + + const conversionEscrow = new Program( + idl as ConversionEscrow, + programId, + provider, + undefined, + () => conversionEscrowResolvers + ) as Program; + + return conversionEscrow; +} diff --git a/packages/conversion-escrow-sdk/src/pdas.ts b/packages/conversion-escrow-sdk/src/pdas.ts new file mode 100644 index 000000000..ac8609594 --- /dev/null +++ b/packages/conversion-escrow-sdk/src/pdas.ts @@ -0,0 +1,17 @@ +import { PublicKey } from "@solana/web3.js"; +import { PROGRAM_ID } from "./constants"; + +export function conversionEscrowKey( + mint: PublicKey, + owner: PublicKey, + programId: PublicKey = PROGRAM_ID +) { + return PublicKey.findProgramAddressSync( + [ + Buffer.from("conversion_escrow", "utf-8"), + mint.toBuffer(), + owner.toBuffer(), + ], + programId + ); +} diff --git a/packages/conversion-escrow-sdk/src/resolvers.ts b/packages/conversion-escrow-sdk/src/resolvers.ts new file mode 100644 index 000000000..a94300555 --- /dev/null +++ b/packages/conversion-escrow-sdk/src/resolvers.ts @@ -0,0 +1,15 @@ +import { + ataResolver, + combineResolvers, + heliumCommonResolver +} from "@helium/anchor-resolvers"; + +export const conversionEscrowResolvers = combineResolvers( + heliumCommonResolver, + ataResolver({ + instruction: "initializeEscrowV0", + mint: "mint", + account: "escrow", + owner: "conversionEscrow", + }) +); diff --git a/packages/conversion-escrow-sdk/tsconfig.cjs.json b/packages/conversion-escrow-sdk/tsconfig.cjs.json new file mode 100644 index 000000000..5445b9909 --- /dev/null +++ b/packages/conversion-escrow-sdk/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.cjs.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs" + } +} diff --git a/packages/conversion-escrow-sdk/tsconfig.esm.json b/packages/conversion-escrow-sdk/tsconfig.esm.json new file mode 100644 index 000000000..4b7ba456e --- /dev/null +++ b/packages/conversion-escrow-sdk/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.esm.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types" + } +} diff --git a/packages/conversion-escrow-sdk/tsconfig.json b/packages/conversion-escrow-sdk/tsconfig.json new file mode 100644 index 000000000..9e1a89a8e --- /dev/null +++ b/packages/conversion-escrow-sdk/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.root.json", + "references": [ + { + "path": "../idls" + }, + { + "path": "../anchor-resolvers" + }, + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + } + ] +} diff --git a/packages/conversion-escrow-sdk/yarn.deploy.lock b/packages/conversion-escrow-sdk/yarn.deploy.lock new file mode 100644 index 000000000..e7809601a --- /dev/null +++ b/packages/conversion-escrow-sdk/yarn.deploy.lock @@ -0,0 +1,2008 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"@babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.22.6": + version: 7.22.11 + resolution: "@babel/runtime@npm:7.22.11" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: a5cd6683a8fcdb8065cb1677f221e22f6c67ec8f15ad1d273b180b93ab3bd86c66da2c48f500d4e72d8d2cfa85ff4872a3f350e5aa3855630036af5da765c001 + languageName: node + linkType: hard + +"@coral-xyz/anchor@npm:^0.28.0": + version: 0.28.0 + resolution: "@coral-xyz/anchor@npm:0.28.0" + dependencies: + "@coral-xyz/borsh": "npm:^0.28.0" + "@solana/web3.js": "npm:^1.68.0" + base64-js: "npm:^1.5.1" + bn.js: "npm:^5.1.2" + bs58: "npm:^4.0.1" + buffer-layout: "npm:^1.2.2" + camelcase: "npm:^6.3.0" + cross-fetch: "npm:^3.1.5" + crypto-hash: "npm:^1.3.0" + eventemitter3: "npm:^4.0.7" + js-sha256: "npm:^0.9.0" + pako: "npm:^2.0.3" + snake-case: "npm:^3.0.4" + superstruct: "npm:^0.15.4" + toml: "npm:^3.0.0" + checksum: 58b3677b5b2ce2c779045184ce4a0ef696966a6a58f41c1c56f6f178db0491acecb6ec677ce0502f0b382a2c724f9c2860d82cc88601784d556d95fbeda415e5 + languageName: node + linkType: hard + +"@coral-xyz/borsh@npm:^0.28.0": + version: 0.28.0 + resolution: "@coral-xyz/borsh@npm:0.28.0" + dependencies: + bn.js: "npm:^5.1.2" + buffer-layout: "npm:^1.2.0" + peerDependencies: + "@solana/web3.js": ^1.68.0 + checksum: bc2b06b777f9ed43d3b886d2350826bd44d5b932c4fd4471af5956e8755236f5854938c890ee4986d88f61d1439e1d84e715c43dcb6dca4e76198c1ce8dc7a58 + languageName: node + linkType: hard + +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": "npm:0.3.9" + checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + languageName: node + linkType: hard + +"@helium/anchor-resolvers@npm:^0.6.42": + version: 0.6.42 + resolution: "@helium/anchor-resolvers@npm:0.6.42" + dependencies: + "@solana/spl-token": ^0.3.8 + "@solana/web3.js": ^1.78.4 + peerDependencies: + "@coral-xyz/anchor": ^0.28.0 + checksum: 25ceab8b1cb6a68fd95c5bf2d57f7a5faf5b473504d1e056588f0f6f8cf21401bb9edd84fb5df6d360af6198f1395d02f1a2e40b57f8da164677e8fb741d110a + languageName: node + linkType: hard + +"@helium/conversion-escrow-sdk@workspace:.": + version: 0.0.0-use.local + resolution: "@helium/conversion-escrow-sdk@workspace:." + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@helium/anchor-resolvers": ^0.6.42 + "@helium/idls": ^0.6.42 + bn.js: ^5.2.0 + bs58: ^4.0.1 + git-format-staged: ^2.1.3 + ts-loader: ^9.2.3 + ts-node: ^10.9.1 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + +"@helium/idls@npm:^0.6.42": + version: 0.6.42 + resolution: "@helium/idls@npm:0.6.42" + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@solana/web3.js": ^1.78.4 + bn.js: ^5.2.0 + borsh: ^0.7.0 + bs58: ^4.0.1 + checksum: 7285ccb1b171c2490f5d4071ff21d37c2ecccbd02d0499c007ee32b185c628b85c642cfcc3a020fe899434cbefcf45dbfacb69b9d6024c3be10576d43e9c2039 + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.1.1 + resolution: "@jridgewell/resolve-uri@npm:3.1.1" + checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.0.3" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef + languageName: node + linkType: hard + +"@noble/curves@npm:^1.0.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: bb798d7a66d8e43789e93bc3c2ddff91a1e19fdb79a99b86cd98f1e5eff0ee2024a2672902c2576ef3577b6f282f3b5c778bebd55761ddbb30e36bf275e83dd0 + languageName: node + linkType: hard + +"@noble/hashes@npm:1.3.2, @noble/hashes@npm:^1.3.1": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.0 + resolution: "@npmcli/fs@npm:3.1.0" + dependencies: + semver: "npm:^7.3.5" + checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f + languageName: node + linkType: hard + +"@solana/buffer-layout-utils@npm:^0.2.0": + version: 0.2.0 + resolution: "@solana/buffer-layout-utils@npm:0.2.0" + dependencies: + "@solana/buffer-layout": "npm:^4.0.0" + "@solana/web3.js": "npm:^1.32.0" + bigint-buffer: "npm:^1.1.5" + bignumber.js: "npm:^9.0.1" + checksum: 9284242245b18b49577195ba7548263850be865a4a2d183944fa01bb76382039db589aab8473698e9bb734b515ada9b4d70db0a72e341c5d567c59b83d6d0840 + languageName: node + linkType: hard + +"@solana/buffer-layout@npm:^4.0.0": + version: 4.0.1 + resolution: "@solana/buffer-layout@npm:4.0.1" + dependencies: + buffer: "npm:~6.0.3" + checksum: bf846888e813187243d4008a7a9f58b49d16cbd995b9d7f1b72898aa510ed77b1ce5e8468e7b2fd26dd81e557a4e74a666e21fccb95f123c1f740d41138bbacd + languageName: node + linkType: hard + +"@solana/spl-token@npm:^0.3.8": + version: 0.3.8 + resolution: "@solana/spl-token@npm:0.3.8" + dependencies: + "@solana/buffer-layout": "npm:^4.0.0" + "@solana/buffer-layout-utils": "npm:^0.2.0" + buffer: "npm:^6.0.3" + peerDependencies: + "@solana/web3.js": ^1.47.4 + checksum: 01f4f87112b0ad277701a3bcb8e03069b69449b92724b17959107686731082bfd3475b5f105e1e8f04badd2e810a43d5ef811744ced5178eea1232de8fd75147 + languageName: node + linkType: hard + +"@solana/web3.js@npm:^1.32.0, @solana/web3.js@npm:^1.68.0, @solana/web3.js@npm:^1.78.4": + version: 1.78.4 + resolution: "@solana/web3.js@npm:1.78.4" + dependencies: + "@babel/runtime": "npm:^7.22.6" + "@noble/curves": "npm:^1.0.0" + "@noble/hashes": "npm:^1.3.1" + "@solana/buffer-layout": "npm:^4.0.0" + agentkeepalive: "npm:^4.3.0" + bigint-buffer: "npm:^1.1.5" + bn.js: "npm:^5.2.1" + borsh: "npm:^0.7.0" + bs58: "npm:^4.0.1" + buffer: "npm:6.0.3" + fast-stable-stringify: "npm:^1.0.0" + jayson: "npm:^4.1.0" + node-fetch: "npm:^2.6.12" + rpc-websockets: "npm:^7.5.1" + superstruct: "npm:^0.14.2" + checksum: e1c44c6cbec87cdfd4d6d23b4241b746e14ed3a9ca73d596693758d91ac825cecf579345da3b0b7bb5e54b6794791bc0eac02cadf11f1ec79e859b6536f26f11 + languageName: node + linkType: hard + +"@tootallnate/once@npm:2": + version: 2.0.0 + resolution: "@tootallnate/once@npm:2.0.0" + checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 + languageName: node + linkType: hard + +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.9 + resolution: "@tsconfig/node10@npm:1.0.9" + checksum: a33ae4dc2a621c0678ac8ac4bceb8e512ae75dac65417a2ad9b022d9b5411e863c4c198b6ba9ef659e14b9fb609bbec680841a2e84c1172df7a5ffcf076539df + languageName: node + linkType: hard + +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a + languageName: node + linkType: hard + +"@tsconfig/node14@npm:^1.0.0": + version: 1.0.3 + resolution: "@tsconfig/node14@npm:1.0.3" + checksum: 19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d + languageName: node + linkType: hard + +"@tsconfig/node16@npm:^1.0.2": + version: 1.0.4 + resolution: "@tsconfig/node16@npm:1.0.4" + checksum: 202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff + languageName: node + linkType: hard + +"@types/connect@npm:^3.4.33": + version: 3.4.35 + resolution: "@types/connect@npm:3.4.35" + dependencies: + "@types/node": "npm:*" + checksum: fe81351470f2d3165e8b12ce33542eef89ea893e36dd62e8f7d72566dfb7e448376ae962f9f3ea888547ce8b55a40020ca0e01d637fab5d99567673084542641 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 20.5.7 + resolution: "@types/node@npm:20.5.7" + checksum: fc284c8e16ddc04569730d58e87eae349eb1c3dd9020cb79a1862d9d9add6f04e7367a236f3252db8db2572f90278e250f4cd43d27d264972b54394eaba1ed76 + languageName: node + linkType: hard + +"@types/node@npm:^12.12.54": + version: 12.20.55 + resolution: "@types/node@npm:12.20.55" + checksum: e4f86785f4092706e0d3b0edff8dca5a13b45627e4b36700acd8dfe6ad53db71928c8dee914d4276c7fd3b6ccd829aa919811c9eb708a2c8e4c6eb3701178c37 + languageName: node + linkType: hard + +"@types/ws@npm:^7.4.4": + version: 7.4.7 + resolution: "@types/ws@npm:7.4.7" + dependencies: + "@types/node": "npm:*" + checksum: b4c9b8ad209620c9b21e78314ce4ff07515c0cadab9af101c1651e7bfb992d7fd933bd8b9c99d110738fd6db523ed15f82f29f50b45510288da72e964dedb1a3 + languageName: node + linkType: hard + +"JSONStream@npm:^1.3.5": + version: 1.3.5 + resolution: "JSONStream@npm:1.3.5" + dependencies: + jsonparse: "npm:^1.2.0" + through: "npm:>=2.2.7 <3" + bin: + JSONStream: ./bin.js + checksum: 2605fa124260c61bad38bb65eba30d2f72216a78e94d0ab19b11b4e0327d572b8d530c0c9cc3b0764f727ad26d39e00bf7ebad57781ca6368394d73169c59e46 + languageName: node + linkType: hard + +"abbrev@npm:^1.0.0": + version: 1.1.1 + resolution: "abbrev@npm:1.1.1" + checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.1.1": + version: 8.2.0 + resolution: "acorn-walk@npm:8.2.0" + checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + languageName: node + linkType: hard + +"acorn@npm:^8.4.1": + version: 8.10.0 + resolution: "acorn@npm:8.10.0" + bin: + acorn: bin/acorn + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + languageName: node + linkType: hard + +"agent-base@npm:6, agent-base@npm:^6.0.2": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + languageName: node + linkType: hard + +"agentkeepalive@npm:^4.2.1, agentkeepalive@npm:^4.3.0": + version: 4.5.0 + resolution: "agentkeepalive@npm:4.5.0" + dependencies: + humanize-ms: "npm:^1.2.1" + checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 + languageName: node + linkType: hard + +"aproba@npm:^1.0.3 || ^2.0.0": + version: 2.0.0 + resolution: "aproba@npm:2.0.0" + checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 + languageName: node + linkType: hard + +"are-we-there-yet@npm:^3.0.0": + version: 3.0.1 + resolution: "are-we-there-yet@npm:3.0.1" + dependencies: + delegates: "npm:^1.0.0" + readable-stream: "npm:^3.6.0" + checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 + languageName: node + linkType: hard + +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 544af8dd3f60546d3e4aff084d451b96961d2267d668670199692f8d054f0415d86fc5497d0e641e91546f0aa920e7c29e5250e99fc89f5552a34b5d93b77f43 + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"base-x@npm:^3.0.2": + version: 3.0.9 + resolution: "base-x@npm:3.0.9" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 957101d6fd09e1903e846fd8f69fd7e5e3e50254383e61ab667c725866bec54e5ece5ba49ce385128ae48f9ec93a26567d1d5ebb91f4d56ef4a9cc0d5a5481e8 + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"bigint-buffer@npm:^1.1.5": + version: 1.1.5 + resolution: "bigint-buffer@npm:1.1.5" + dependencies: + bindings: "npm:^1.3.0" + node-gyp: "npm:latest" + checksum: d010c9f57758bcdaccb435d88b483ffcc95fe8bbc6e7fb3a44fb5221f29c894ffaf4a3c5a4a530e0e7d6608203c2cde9b79ee4f2386cd6d4462d1070bc8c9f4e + languageName: node + linkType: hard + +"bignumber.js@npm:^9.0.1": + version: 9.1.2 + resolution: "bignumber.js@npm:9.1.2" + checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf + languageName: node + linkType: hard + +"bindings@npm:^1.3.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: "npm:1.0.0" + checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 + languageName: node + linkType: hard + +"bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 + languageName: node + linkType: hard + +"borsh@npm:^0.7.0": + version: 0.7.0 + resolution: "borsh@npm:0.7.0" + dependencies: + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.0" + text-encoding-utf-8: "npm:^1.0.2" + checksum: e98bfb5f7cfb820819c2870b884dac58dd4b4ce6a86c286c8fbf5c9ca582e73a8c6094df67e81a28c418ff07a309c6b118b2e27fdfea83fd92b8100c741da0b5 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + languageName: node + linkType: hard + +"braces@npm:^3.0.2": + version: 3.0.2 + resolution: "braces@npm:3.0.2" + dependencies: + fill-range: "npm:^7.0.1" + checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 + languageName: node + linkType: hard + +"bs58@npm:^4.0.0, bs58@npm:^4.0.1": + version: 4.0.1 + resolution: "bs58@npm:4.0.1" + dependencies: + base-x: "npm:^3.0.2" + checksum: b3c5365bb9e0c561e1a82f1a2d809a1a692059fae016be233a6127ad2f50a6b986467c3a50669ce4c18929dcccb297c5909314dd347a25a68c21b68eb3e95ac2 + languageName: node + linkType: hard + +"buffer-layout@npm:^1.2.0, buffer-layout@npm:^1.2.2": + version: 1.2.2 + resolution: "buffer-layout@npm:1.2.2" + checksum: e5809ba275530bf4e52fd09558b7c2111fbda5b405124f581acf364261d9c154e271800271898cd40473f9bcbb42c31584efb04219bde549d3460ca4bafeaa07 + languageName: node + linkType: hard + +"buffer@npm:6.0.3, buffer@npm:^6.0.3, buffer@npm:~6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.2.1" + checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 + languageName: node + linkType: hard + +"bufferutil@npm:^4.0.1": + version: 4.0.7 + resolution: "bufferutil@npm:4.0.7" + dependencies: + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.3.0" + checksum: f75aa87e3d1b99b87a95f60a855e63f70af07b57fb8443e75a2ddfef2e47788d130fdd46e3a78fd7e0c10176082b26dfbed970c5b8632e1cc299cafa0e93ce45 + languageName: node + linkType: hard + +"cacache@npm:^17.0.0": + version: 17.1.4 + resolution: "cacache@npm:17.1.4" + dependencies: + "@npmcli/fs": "npm:^3.1.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^7.7.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^1.0.2" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^4.0.0" + ssri: "npm:^10.0.0" + tar: "npm:^6.1.11" + unique-filename: "npm:^3.0.0" + checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 + languageName: node + linkType: hard + +"camelcase@npm:^6.3.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d + languageName: node + linkType: hard + +"chalk@npm:^4.1.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"color-support@npm:^1.1.3": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + languageName: node + linkType: hard + +"commander@npm:^2.20.3": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + languageName: node + linkType: hard + +"console-control-strings@npm:^1.1.0": + version: 1.1.0 + resolution: "console-control-strings@npm:1.1.0" + checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + languageName: node + linkType: hard + +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff + languageName: node + linkType: hard + +"cross-fetch@npm:^3.1.5": + version: 3.1.8 + resolution: "cross-fetch@npm:3.1.8" + dependencies: + node-fetch: "npm:^2.6.12" + checksum: 78f993fa099eaaa041122ab037fe9503ecbbcb9daef234d1d2e0b9230a983f64d645d088c464e21a247b825a08dc444a6e7064adfa93536d3a9454b4745b3632 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.0": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + languageName: node + linkType: hard + +"crypto-hash@npm:^1.3.0": + version: 1.3.0 + resolution: "crypto-hash@npm:1.3.0" + checksum: a3a507e0d2b18fbd2da8088a1c62d0c53c009a99bbfa6d851cac069734ffa546922fa51bdd776d006459701cdda873463e5059ece3431aca048fd99e7573d138 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.3": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: "npm:2.1.2" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + +"delay@npm:^5.0.0": + version: 5.0.0 + resolution: "delay@npm:5.0.0" + checksum: 62f151151ecfde0d9afbb8a6be37a6d103c4cb24f35a20ef3fe56f920b0d0d0bb02bc9c0a3084d0179ef669ca332b91155f2ee4d9854622cd2cdba5fc95285f9 + languageName: node + linkType: hard + +"delegates@npm:^1.0.0": + version: 1.0.0 + resolution: "delegates@npm:1.0.0" + checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd + languageName: node + linkType: hard + +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: f2c09b0ce4e6b301c221addd83bf3f454c0bc00caa3dd837cf6c127d6edf7223aa2bbe3b688feea110b7f262adbfc845b757c44c8a9f8c0c5b15d8fa9ce9d20d + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: a65e3519414856df0228b9f645332f974f2bf5433370f544a681122eab59e66038fc3349b4be1cdc47152779dac71a5864f1ccda2f745e767c46e9c6543b1169 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + languageName: node + linkType: hard + +"enhanced-resolve@npm:^5.0.0": + version: 5.15.0 + resolution: "enhanced-resolve@npm:5.15.0" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: fbd8cdc9263be71cc737aa8a7d6c57b43d6aa38f6cc75dde6fcd3598a130cc465f979d2f4d01bb3bf475acb43817749c79f8eef9be048683602ca91ab52e4f11 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + languageName: node + linkType: hard + +"es6-promise@npm:^4.0.3": + version: 4.2.8 + resolution: "es6-promise@npm:4.2.8" + checksum: 95614a88873611cb9165a85d36afa7268af5c03a378b35ca7bda9508e1d4f1f6f19a788d4bc755b3fd37c8ebba40782018e02034564ff24c9d6fa37e959ad57d + languageName: node + linkType: hard + +"es6-promisify@npm:^5.0.0": + version: 5.0.0 + resolution: "es6-promisify@npm:5.0.0" + dependencies: + es6-promise: "npm:^4.0.3" + checksum: fbed9d791598831413be84a5374eca8c24800ec71a16c1c528c43a98e2dadfb99331483d83ae6094ddb9b87e6f799a15d1553cebf756047e0865c753bc346b92 + languageName: node + linkType: hard + +"eventemitter3@npm:^4.0.7": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 + languageName: node + linkType: hard + +"eyes@npm:^0.1.8": + version: 0.1.8 + resolution: "eyes@npm:0.1.8" + checksum: c31703a92bf36ba75ee8d379ee7985c24ee6149f3a6175f44cec7a05b178c38bce9836d3ca48c9acb0329a960ac2c4b2ead4e60cdd4fe6e8c92cad7cd6913687 + languageName: node + linkType: hard + +"fast-stable-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "fast-stable-stringify@npm:1.0.0" + checksum: ef1203d246a7e8ac15e2bfbda0a89fa375947bccf9f7910be0ea759856dbe8ea5024a0d8cc2cceabe18a9cb67e95927b78bb6173a3ae37ec55a518cf36e5244b + languageName: node + linkType: hard + +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 + languageName: node + linkType: hard + +"fill-range@npm:^7.0.1": + version: 7.0.1 + resolution: "fill-range@npm:7.0.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + languageName: node + linkType: hard + +"gauge@npm:^4.0.3": + version: 4.0.4 + resolution: "gauge@npm:4.0.4" + dependencies: + aproba: "npm:^1.0.3 || ^2.0.0" + color-support: "npm:^1.1.3" + console-control-strings: "npm:^1.1.0" + has-unicode: "npm:^2.0.1" + signal-exit: "npm:^3.0.7" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + wide-align: "npm:^1.1.5" + checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d + languageName: node + linkType: hard + +"git-format-staged@npm:^2.1.3": + version: 2.1.3 + resolution: "git-format-staged@npm:2.1.3" + bin: + git-format-staged: git-format-staged + checksum: 749da68f0d9bf24db53b87a5f1613fc1a8790801d7c3ccb31d02b94d99f4cf2450126ef565f16adcc0649fbbf90dc44b4f009d4f99ff8a26921ba754bdb09b31 + languageName: node + linkType: hard + +"glob@npm:^10.2.2": + version: 10.3.3 + resolution: "glob@npm:10.3.3" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.0.3" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/cjs/src/bin.js + checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 + languageName: node + linkType: hard + +"glob@npm:^7.1.3, glob@npm:^7.1.4": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.1.1" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"has-unicode@npm:^2.0.1": + version: 2.0.1 + resolution: "has-unicode@npm:2.0.1" + checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^5.0.0": + version: 5.0.0 + resolution: "http-proxy-agent@npm:5.0.0" + dependencies: + "@tootallnate/once": "npm:2" + agent-base: "npm:6" + debug: "npm:4" + checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^5.0.0": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + languageName: node + linkType: hard + +"humanize-ms@npm:^1.2.1": + version: 1.2.1 + resolution: "humanize-ms@npm:1.2.1" + dependencies: + ms: "npm:^2.0.0" + checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + languageName: node + linkType: hard + +"ieee754@npm:^1.2.1": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + languageName: node + linkType: hard + +"inherits@npm:2, inherits@npm:^2.0.3": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + languageName: node + linkType: hard + +"ip@npm:^2.0.0": + version: 2.0.0 + resolution: "ip@npm:2.0.0" + checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + languageName: node + linkType: hard + +"isomorphic-ws@npm:^4.0.1": + version: 4.0.1 + resolution: "isomorphic-ws@npm:4.0.1" + peerDependencies: + ws: "*" + checksum: d7190eadefdc28bdb93d67b5f0c603385aaf87724fa2974abb382ac1ec9756ed2cfb27065cbe76122879c2d452e2982bc4314317f3d6c737ddda6c047328771a + languageName: node + linkType: hard + +"jackspeak@npm:^2.0.3": + version: 2.3.1 + resolution: "jackspeak@npm:2.3.1" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 34ea4d618d8d36ac104fe1053c85dfb6a63306cfe87e157ef42f18a7aa30027887370a4e163dd4993e45c6bf8a8ae003bf8476fdb8538e8ee5cd1938c27b15d0 + languageName: node + linkType: hard + +"jayson@npm:^4.1.0": + version: 4.1.0 + resolution: "jayson@npm:4.1.0" + dependencies: + "@types/connect": "npm:^3.4.33" + "@types/node": "npm:^12.12.54" + "@types/ws": "npm:^7.4.4" + JSONStream: "npm:^1.3.5" + commander: "npm:^2.20.3" + delay: "npm:^5.0.0" + es6-promisify: "npm:^5.0.0" + eyes: "npm:^0.1.8" + isomorphic-ws: "npm:^4.0.1" + json-stringify-safe: "npm:^5.0.1" + uuid: "npm:^8.3.2" + ws: "npm:^7.4.5" + bin: + jayson: bin/jayson.js + checksum: 86464322fbdc6db65d2bb4fc278cb6c86fad5c2a506065490d39459f09ba0d30f2b4fb740b33828a1424791419b6c8bd295dc54d361a4ad959bf70cc62b1ca7e + languageName: node + linkType: hard + +"js-sha256@npm:^0.9.0": + version: 0.9.0 + resolution: "js-sha256@npm:0.9.0" + checksum: ffad54b3373f81581e245866abfda50a62c483803a28176dd5c28fd2d313e0bdf830e77dac7ff8afd193c53031618920f3d98daf21cbbe80082753ab639c0365 + languageName: node + linkType: hard + +"json-stringify-safe@npm:^5.0.1": + version: 5.0.1 + resolution: "json-stringify-safe@npm:5.0.1" + checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee + languageName: node + linkType: hard + +"jsonparse@npm:^1.2.0": + version: 1.3.1 + resolution: "jsonparse@npm:1.3.1" + checksum: 6514a7be4674ebf407afca0eda3ba284b69b07f9958a8d3113ef1005f7ec610860c312be067e450c569aab8b89635e332cee3696789c750692bb60daba627f4d + languageName: node + linkType: hard + +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 83a0a5f159ad7614bee8bf976b96275f3954335a84fad2696927f609ddae902802c4f3312d86668722e668bef41400254807e1d3a7f2e8c3eede79691aa1f010 + languageName: node + linkType: hard + +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: "npm:^4.0.0" + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + languageName: node + linkType: hard + +"lru-cache@npm:^7.7.1": + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 + languageName: node + linkType: hard + +"lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.0.1 + resolution: "lru-cache@npm:10.0.1" + checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 + languageName: node + linkType: hard + +"make-error@npm:^1.1.1": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 + languageName: node + linkType: hard + +"make-fetch-happen@npm:^11.0.3": + version: 11.1.1 + resolution: "make-fetch-happen@npm:11.1.1" + dependencies: + agentkeepalive: "npm:^4.2.1" + cacache: "npm:^17.0.0" + http-cache-semantics: "npm:^4.1.1" + http-proxy-agent: "npm:^5.0.0" + https-proxy-agent: "npm:^5.0.0" + is-lambda: "npm:^1.0.1" + lru-cache: "npm:^7.7.1" + minipass: "npm:^5.0.0" + minipass-fetch: "npm:^3.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^0.6.3" + promise-retry: "npm:^2.0.1" + socks-proxy-agent: "npm:^7.0.0" + ssri: "npm:^10.0.0" + checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.0": + version: 4.0.5 + resolution: "micromatch@npm:4.0.5" + dependencies: + braces: "npm:^3.0.2" + picomatch: "npm:^2.3.1" + checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc + languageName: node + linkType: hard + +"minimatch@npm:^3.1.1": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + +"minimatch@npm:^9.0.1": + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 + languageName: node + linkType: hard + +"minipass-collect@npm:^1.0.2": + version: 1.0.2 + resolution: "minipass-collect@npm:1.0.2" + dependencies: + minipass: "npm:^3.0.0" + checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.4 + resolution: "minipass-fetch@npm:3.0.4" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^2.1.2" + dependenciesMeta: + encoding: + optional: true + checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": + version: 7.0.3 + resolution: "minipass@npm:7.0.3" + checksum: 6f1614f5b5b55568a46bca5fec0e7c46dac027691db27d0e1923a8192866903144cd962ac772c0e9f89b608ea818b702709c042bce98e190d258847d85461531 + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + languageName: node + linkType: hard + +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + languageName: node + linkType: hard + +"ms@npm:^2.0.0": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + languageName: node + linkType: hard + +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: "npm:^2.0.2" + tslib: "npm:^2.0.3" + checksum: 0b2ebc113dfcf737d48dde49cfebf3ad2d82a8c3188e7100c6f375e30eafbef9e9124aadc3becef237b042fd5eb0aad2fd78669c20972d045bbe7fea8ba0be5c + languageName: node + linkType: hard + +"node-fetch@npm:^2.6.12": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 + languageName: node + linkType: hard + +"node-gyp-build@npm:^4.3.0": + version: 4.6.1 + resolution: "node-gyp-build@npm:4.6.1" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: c3676d337b36803bc7792e35bf7fdcda7cdcb7e289b8f9855a5535702a82498eb976842fefcf487258c58005ca32ce3d537fbed91280b04409161dcd7232a882 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 9.4.0 + resolution: "node-gyp@npm:9.4.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^7.1.4" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^11.0.3" + nopt: "npm:^6.0.0" + npmlog: "npm:^6.0.0" + rimraf: "npm:^3.0.2" + semver: "npm:^7.3.5" + tar: "npm:^6.1.2" + which: "npm:^2.0.2" + bin: + node-gyp: bin/node-gyp.js + checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 + languageName: node + linkType: hard + +"nopt@npm:^6.0.0": + version: 6.0.0 + resolution: "nopt@npm:6.0.0" + dependencies: + abbrev: "npm:^1.0.0" + bin: + nopt: bin/nopt.js + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + languageName: node + linkType: hard + +"npmlog@npm:^6.0.0": + version: 6.0.2 + resolution: "npmlog@npm:6.0.2" + dependencies: + are-we-there-yet: "npm:^3.0.0" + console-control-strings: "npm:^1.1.0" + gauge: "npm:^4.0.3" + set-blocking: "npm:^2.0.0" + checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + languageName: node + linkType: hard + +"once@npm:^1.3.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + +"pako@npm:^2.0.3": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" + dependencies: + lru-cache: "npm:^9.1.1 || ^10.0.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 + languageName: node + linkType: hard + +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + languageName: node + linkType: hard + +"readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.0 + resolution: "regenerator-runtime@npm:0.14.0" + checksum: 1c977ad82a82a4412e4f639d65d22be376d3ebdd30da2c003eeafdaaacd03fc00c2320f18120007ee700900979284fc78a9f00da7fb593f6e6eeebc673fba9a3 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + languageName: node + linkType: hard + +"rimraf@npm:^3.0.2": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: "npm:^7.1.3" + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + +"rpc-websockets@npm:^7.5.1": + version: 7.6.0 + resolution: "rpc-websockets@npm:7.6.0" + dependencies: + "@babel/runtime": "npm:^7.17.2" + bufferutil: "npm:^4.0.1" + eventemitter3: "npm:^4.0.7" + utf-8-validate: "npm:^5.0.2" + uuid: "npm:^8.3.2" + ws: "npm:^8.5.0" + dependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: af2b254f65985610bd354e8e13de07b5a36010b94672b0b5a9d226b9bb1b8b17d01c63221cad97263845888f3610e55867a32e4c0017dfb92fddf89417c4cb6c + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + +"semver@npm:^7.3.4, semver@npm:^7.3.5": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.7": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + languageName: node + linkType: hard + +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 0a7a79900bbb36f8aaa922cf111702a3647ac6165736d5dc96d3ef367efc50465cac70c53cd172c382b022dac72ec91710608e5393de71f76d7142e6fd80e8a3 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^7.0.0": + version: 7.0.0 + resolution: "socks-proxy-agent@npm:7.0.0" + dependencies: + agent-base: "npm:^6.0.2" + debug: "npm:^4.3.3" + socks: "npm:^2.6.2" + checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + languageName: node + linkType: hard + +"socks@npm:^2.6.2": + version: 2.7.1 + resolution: "socks@npm:2.7.1" + dependencies: + ip: "npm:^2.0.0" + smart-buffer: "npm:^4.2.0" + checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.5 + resolution: "ssri@npm:10.0.5" + dependencies: + minipass: "npm:^7.0.3" + checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d + languageName: node + linkType: hard + +"superstruct@npm:^0.14.2": + version: 0.14.2 + resolution: "superstruct@npm:0.14.2" + checksum: c5c4840f432da82125b923ec45faca5113217e83ae416e314d80eae012b8bb603d2e745025d173450758d116348820bc7028157f8c9a72b6beae879f94b837c0 + languageName: node + linkType: hard + +"superstruct@npm:^0.15.4": + version: 0.15.5 + resolution: "superstruct@npm:0.15.5" + checksum: 6d1f5249fee789424b7178fa0a1ffb2ace629c5480c39505885bd8c0046a4ff8b267569a3442fa53b8c560a7ba6599cf3f8af94225aebeb2cf6023f7dd911050 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + languageName: node + linkType: hard + +"tapable@npm:^2.2.0": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 + languageName: node + linkType: hard + +"tar@npm:^6.1.11, tar@npm:^6.1.2": + version: 6.1.15 + resolution: "tar@npm:6.1.15" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 + languageName: node + linkType: hard + +"text-encoding-utf-8@npm:^1.0.2": + version: 1.0.2 + resolution: "text-encoding-utf-8@npm:1.0.2" + checksum: ec4c15d50e738c5dba7327ad432ebf0725ec75d4d69c0bd55609254c5a3bc5341272d7003691084a0a73d60d981c8eb0e87603676fdb6f3fed60f4c9192309f9 + languageName: node + linkType: hard + +"through@npm:>=2.2.7 <3": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + languageName: node + linkType: hard + +"toml@npm:^3.0.0": + version: 3.0.0 + resolution: "toml@npm:3.0.0" + checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f + languageName: node + linkType: hard + +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + +"ts-loader@npm:^9.2.3": + version: 9.4.4 + resolution: "ts-loader@npm:9.4.4" + dependencies: + chalk: "npm:^4.1.0" + enhanced-resolve: "npm:^5.0.0" + micromatch: "npm:^4.0.0" + semver: "npm:^7.3.4" + peerDependencies: + typescript: "*" + webpack: ^5.0.0 + checksum: 8e5e6b839b0edfa40d2156c880d88ccab58226894ea5978221bc48c7db3215e2e856bfd0093f148e925a2befc42d6c94cafa9a994a7da274541efaa916012b63 + languageName: node + linkType: hard + +"ts-node@npm:^10.9.1": + version: 10.9.1 + resolution: "ts-node@npm:10.9.1" + dependencies: + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 090adff1302ab20bd3486e6b4799e90f97726ed39e02b39e566f8ab674fd5bd5f727f43615debbfc580d33c6d9d1c6b1b3ce7d8e3cca3e20530a145ffa232c35 + languageName: node + linkType: hard + +"tslib@npm:^2.0.3": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad + languageName: node + linkType: hard + +"typescript@npm:^5.2.2": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c + languageName: node + linkType: hard + +"typescript@patch:typescript@^5.2.2#~builtin": + version: 5.2.2 + resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f3b441" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 0f4da2f15e6f1245e49db15801dbee52f2bbfb267e1c39225afdab5afee1a72839cd86000e65ee9d7e4dfaff12239d28beaf5ee431357fcced15fb08583d72ca + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: "npm:^4.0.0" + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + languageName: node + linkType: hard + +"utf-8-validate@npm:^5.0.2": + version: 5.0.10 + resolution: "utf-8-validate@npm:5.0.10" + dependencies: + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.3.0" + checksum: 5579350a023c66a2326752b6c8804cc7b39dcd251bb088241da38db994b8d78352e388dcc24ad398ab98385ba3c5ffcadb6b5b14b2637e43f767869055e46ba6 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 78089ad549e21bcdbfca10c08850022b22024cdcc2da9b168bcf5a73a6ed7bf01a9cebb9eac28e03cd23a684d81e0502797e88f3ccd27a32aeab1cfc44c39da0 + languageName: node + linkType: hard + +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + +"which@npm:^2.0.1, which@npm:^2.0.2": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + languageName: node + linkType: hard + +"wide-align@npm:^1.1.5": + version: 1.1.5 + resolution: "wide-align@npm:1.1.5" + dependencies: + string-width: "npm:^1.0.2 || 2 || 3 || 4" + checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"ws@npm:^7.4.5": + version: 7.5.9 + resolution: "ws@npm:7.5.9" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: c3c100a181b731f40b7f2fddf004aa023f79d64f489706a28bc23ff88e87f6a64b3c6651fbec3a84a53960b75159574d7a7385709847a62ddb7ad6af76f49138 + languageName: node + linkType: hard + +"ws@npm:^8.5.0": + version: 8.13.0 + resolution: "ws@npm:8.13.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + languageName: node + linkType: hard + +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 + languageName: node + linkType: hard diff --git a/packages/distributor-oracle/src/client.ts b/packages/distributor-oracle/src/client.ts index 5245d8bb0..5a13fa640 100644 --- a/packages/distributor-oracle/src/client.ts +++ b/packages/distributor-oracle/src/client.ts @@ -277,18 +277,22 @@ export async function formBulkTransactions({ assetEndpoint || provider.connection.rpcEndpoint, assets ); + const willPay = (await axios.get( + `${lazyDistributorAcc.oracles[0].url}/will-pay-recipient` + )).data.willPay; let ixsPerAsset = await Promise.all( recipientAccs.map(async (recipientAcc, idx) => { if (!recipientAcc) { return [ - await ( + await( await initializeCompressionRecipient({ program: lazyDistributorProgram, assetId: assets![idx], lazyDistributor, assetEndpoint, owner: wallet, - payer, + // Temporarily set oracle as the payer to subsidize new HNT wallets. + payer: willPay ? lazyDistributorAcc.oracles[0].oracle : payer, getAssetFn: () => Promise.resolve(compressionAssetAccs![idx]), // cache result so we don't hit again getAssetProofFn: assetProofsById ? () => @@ -522,6 +526,9 @@ export async function formTransaction({ const recipientAcc = await lazyDistributorProgram.account.recipientV0.fetchNullable(recipient); if (!recipientAcc) { + const willPay = ( + await axios.get(`${lazyDistributorAcc.oracles[0].url}/will-pay-recipient`) + ).data.willPay; let initRecipientIx; if (assetAcc.compression.compressed) { initRecipientIx = await ( @@ -531,7 +538,7 @@ export async function formTransaction({ lazyDistributor, assetEndpoint, owner: wallet, - payer, + payer: willPay ? lazyDistributorAcc.oracles[0].oracle : payer, getAssetFn: () => Promise.resolve(assetAcc), // cache result so we don't hit again getAssetProofFn, }) diff --git a/packages/distributor-oracle/src/server.ts b/packages/distributor-oracle/src/server.ts index 00afc1285..067cac02d 100644 --- a/packages/distributor-oracle/src/server.ts +++ b/packages/distributor-oracle/src/server.ts @@ -384,15 +384,17 @@ export class OracleServer { if (!(programId.equals(LD_PID) || programId.equals(RO_PID))) { return { success: false, - message: "Invalid instructions in transaction", + message: `Invalid instructions in transaction: ${programId.toBase58()}`, }; } const data = Buffer.from(ix.data); let decoded: Instruction | null; if (programId.equals(LD_PID)) { + console.log("decoding LD", data) decoded = ( this.ldProgram.coder.instruction as BorshInstructionCoder ).decode(data); + console.log("decoded LD", decoded) } else { decoded = ( this.roProgram.coder.instruction as BorshInstructionCoder @@ -411,7 +413,7 @@ export class OracleServer { ) { return { success: false, - message: "Invalid instructions in transaction", + message: `Invalid instructions in transaction: name: ${decoded} ${programId.toBase58()}`, }; } diff --git a/packages/helium-admin-cli/src/create-and-approve-makers.ts b/packages/helium-admin-cli/src/create-and-approve-makers.ts index da75865f4..2406ab098 100644 --- a/packages/helium-admin-cli/src/create-and-approve-makers.ts +++ b/packages/helium-admin-cli/src/create-and-approve-makers.ts @@ -217,6 +217,7 @@ export async function run(args: any = process.argv) { metadataUrl: 'todo', issuingAuthority: makerAuthority, updateAuthority, + topupAmounts: [], }) .accounts({ maker, diff --git a/packages/helium-admin-cli/src/create-common-lut.ts b/packages/helium-admin-cli/src/create-common-lut.ts index 4c18acaf3..abba6b0f9 100644 --- a/packages/helium-admin-cli/src/create-common-lut.ts +++ b/packages/helium-admin-cli/src/create-common-lut.ts @@ -1,5 +1,5 @@ import * as anchor from "@coral-xyz/anchor"; -import { chunks, sendInstructions, truthy, withPriorityFees } from "@helium/spl-utils"; +import { chunks, LUT_ACCOUNTS, sendInstructions, truthy, withPriorityFees } from "@helium/spl-utils"; import { AddressLookupTableProgram, PublicKey, @@ -48,79 +48,7 @@ export async function run(args: any = process.argv) { authority = squads.getAuthorityPDA(multisig, argv.authorityIndex); } - const accounts = [ - // Programs - "1azyuavdMyvsivtNxPoz6SucD18eDHeXzFCUPq5XU7w", - "hdaoVTCqhfHHo75XdAMxBKdUqvq1i5bF23sisBqVgGR", - "credMBJhYFzfn7NxBMdU4aUqFggAjgztaCcv2Fo6fPT", - "hemjuPXBpNvggtaUnN1MwT3wrdhttKEfosTcc2P9Pg8", - "circAbx64bbsscPbQzZAUvuXpHqrCe6fLMzc2uKXz9g", - "treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5", - "1atrmQs3eq1N2FEYWu6tyTXbCjP4uQwExpjtnhXtS8h", - "porcSnvH9pvcYPmQ65Y8qcZSRxQBiBBQX7UV5nmBegy", - "rorcfdX4h9m9swCKgcypaHJ8NGYVANBpmV9EHn3cYrF", - "hvsrNC3NKbcryqDs2DocYHZ9yPKEVzdSjQG6RVtK1s8", - "fanqeMu3fw8R4LwKNbahPtYXJsyLL6NXyfe2BqzhfB6", - "memMa1HG4odAFmUbGWfPwS1WWfK95k99F2YTkGvyxZr", - "hexbnKYoA2GercNNhHUCCfrTRWrHjT6ujKPXTa5NPqJ", - "noEmmgLmQdk6DLiPV8CSwQv3qQDyGEhz9m5A4zhtByv", - "cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w", - "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", - "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", - "11111111111111111111111111111111", - // Lazy distributor IOT - "37eiz5KzYwpAdLgrSh8GT1isKiJ6hcE5ET86dqaoCugL", - // Lazy dist Oracle - "orc1TYY5L4B4ZWDEMayTqu99ikPM9bQo9fqzoaCPP5Q", - // Oracle signer - "7WuVr8SGcZ4KxpHBEdRGVTeSwkhk1WGUXT7DEzvWpYu4", - // Lazy dist mobile - "GZtTp3AUo2AHdQe9BCJ6gXR9KqfruRvHnZ4QiJUALMcz", - // Hnt pyth - "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33", - // Mobile pyth - "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx", - // Usdc pyth - "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", - // Hnt - "hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux", - // dc - "dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm", - // Mobile - "mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6", - // Dao - "BQ3MCuTT5zVBhNfQ4SjMh3NPVhFy73MPV8rjfq5d1zie", - // Mobile subdao - "Gm9xDCJawDEKDrrQW6haw94gABaYzQwCq4ZQU8h8bd22", - // Iot subdao - "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk", - // Mobile Delegator pool - "71Y96vbVWYkoVQUgVsd8LSBRRDrgp5pf1sKznM5KuaA7", - // Mobile Delegator pool circuit breaker - "2cocTPZ7aRT62wTDGkosF98oo4iqCtkZnFdNHWqNZLuS", - // Iot delegator pool - "6fvj6rSwTeCkY7i45jYZYpZEhKmPRSTmA29hUDiMSFtU", - // Iot delegator pool circuit breaker - "6mNUqFAyLBkV88Nj6ctrcv66iJMHwzNzV8XFUwLmGerG", - // Mobile rewardable entity config - "EP1FNydbuKjGopwXVrVLR71NnC9YMRbTg9aHfk3KfMRj", - // Compression proram - "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK", - // Mobile escrow circuit breaker - "4qGj88CX3McdTXEviEaqeP2pnZJxRTsZFWyU3Mrnbku4", - // Mobile escrow - "GD37bnQdGkDsjNqnVGr9qWTnQJSKMHbsiXX9tXLMUcaL", - // Iot escrow - "4po3YMfioHkNP4mL4N46UWJvBoQDS2HFjzGm1ifrUWuZ", - // Iot escrow circuit breaker - "5veMSa4ks66zydSaKSPMhV7H2eF88HvuKDArScNH9jaG", - // Hnt registrar - "BMnWRWZrWqb6JMKznaDqNxWaWAHoaTzVabM6Qwyh3WKz", - // Data credits - "D1LbvrJQ9K2WbGPMbM3Fnrf5PSsDH1TDpjqJdHuvs81n", - ].map((a) => { - return new PublicKey(a); - }); + const accounts = LUT_ACCOUNTS; const slot = await provider.connection.getSlot(); const [lookupTableInst, lookupTableAddress] = diff --git a/packages/helium-admin-cli/src/create-maker.ts b/packages/helium-admin-cli/src/create-maker.ts index 0b070b33c..8b780d4ee 100644 --- a/packages/helium-admin-cli/src/create-maker.ts +++ b/packages/helium-admin-cli/src/create-maker.ts @@ -141,6 +141,7 @@ export async function run(args: any = process.argv) { issuingAuthority, // Temp, since we need to set maker tree updateAuthority: provider.wallet.publicKey, + topupAmounts: [], }) .accounts({ maker, diff --git a/packages/helium-entity-manager-sdk/src/functions/onboardMobileHotspot.ts b/packages/helium-entity-manager-sdk/src/functions/onboardMobileHotspot.ts index 963c24feb..3107b9f13 100644 --- a/packages/helium-entity-manager-sdk/src/functions/onboardMobileHotspot.ts +++ b/packages/helium-entity-manager-sdk/src/functions/onboardMobileHotspot.ts @@ -7,7 +7,7 @@ import { import { PublicKey } from "@solana/web3.js"; import BN from "bn.js"; import { keyToAssetForAsset } from "../helpers"; -import { mobileInfoKey } from "../pdas"; +import { mobileHotspotVoucherKey, mobileInfoKey } from "../pdas"; import { MobileDeploymentInfoV0 } from ".."; export async function onboardMobileHotspot({ @@ -51,28 +51,96 @@ export async function onboardMobileHotspot({ keyToAsset.entityKey ); const makerAcc = await program.account.makerV0.fetchNullable(maker); + const voucherK = mobileHotspotVoucherKey( + rewardableEntityConfig, + keyToAsset.entityKey + )[0]; + const voucher = await program.account.mobileHotspotVoucherV0.fetchNullable( + voucherK + ); + + if (voucher) { + return program.methods + .onboardMobileHotspotV1({ + ...args, + deploymentInfo: deploymentInfo as any, + }) + .preInstructions([ + await program.methods + .payMobileVoucherV0({ + ...args, + }) + .accounts({ + ...accounts, + payer, + rewardableEntityConfig, + hotspotOwner: owner, + maker, + dao, + mobileVoucher: voucherK, + keyToAsset: keyToAssetKey, + }) + .instruction(), + ]) + .postInstructions( + typeof location == "undefined" + ? [] + : [ + await program.methods + .updateMobileInfoV0({ + ...args, + location, + deploymentInfo: null, + }) + .accounts({ + ...accounts, + payer, + rewardableEntityConfig, + hotspotOwner: owner, + dao, - return program.methods - .onboardMobileHotspotV0({ - ...args, - location: typeof location == "undefined" ? null : location, - deviceType: { - [deviceType]: {}, - } as any, - deploymentInfo: deploymentInfo as any, - }) - .accounts({ - // hotspot: assetId, - ...accounts, - dcFeePayer, - payer, - rewardableEntityConfig, - hotspotOwner: owner, - mobileInfo: info, - maker, - dao, - issuingAuthority: makerAcc?.issuingAuthority, - keyToAsset: keyToAssetKey, - }) - .remainingAccounts(remainingAccounts); + mobileInfo: info, + }) + .instruction(), + ] + ) + .accounts({ + // hotspot: assetId, + ...accounts, + payer, + rewardableEntityConfig, + hotspotOwner: owner, + mobileInfo: info, + maker, + dao, + mobileVoucher: voucherK, + refund: voucher.refund, + keyToAsset: keyToAssetKey, + }) + .remainingAccounts(remainingAccounts); + } else { + return program.methods + .onboardMobileHotspotV0({ + ...args, + location: typeof location == "undefined" ? null : location, + deviceType: { + [deviceType]: {}, + } as any, + deploymentInfo: deploymentInfo as any, + }) + .accounts({ + // hotspot: assetId, + ...accounts, + dcFeePayer, + payer, + rewardableEntityConfig, + hotspotOwner: owner, + mobileInfo: info, + maker, + dao, + issuingAuthority: makerAcc?.issuingAuthority, + keyToAsset: keyToAssetKey, + }) + .remainingAccounts(remainingAccounts); + } } diff --git a/packages/helium-entity-manager-sdk/src/functions/topUpMaker.ts b/packages/helium-entity-manager-sdk/src/functions/topUpMaker.ts new file mode 100644 index 000000000..89934eedd --- /dev/null +++ b/packages/helium-entity-manager-sdk/src/functions/topUpMaker.ts @@ -0,0 +1,111 @@ +import { AnchorProvider, Program } from "@coral-xyz/anchor"; +import { conversionEscrowKey } from "@helium/conversion-escrow-sdk"; +import { ConversionEscrow } from "@helium/idls/lib/types/conversion_escrow"; +import { HeliumEntityManager } from "@helium/idls/lib/types/helium_entity_manager"; +import { MOBILE_MINT, MOBILE_PYTH_PRICE_FEED, TransactionDraft, USDC_MINT, USDC_PYTH_PRICE_FEED, toBN, toNumber } from "@helium/spl-utils"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { + PublicKey +} from "@solana/web3.js"; +import { deserializeInstruction } from "./utils"; + +export const JUPITER_URL = + process.env.JUPITER_URL || "https://quote-api.jup.ag/v6"; + +export async function topUpMaker({ + program, + ceProgram, + maker, + usdcMint = USDC_MINT, + payer = (program.provider as AnchorProvider).wallet.publicKey, +}: { + program: Program; + ceProgram: Program; + payer?: PublicKey; + maker: PublicKey; + usdcMint?: PublicKey; +}) { + const makerAcc = await program.account.makerV0.fetch(maker); + return await Promise.all(makerAcc.topupAmounts.map(async (topupAmount) => { + const inputMint = USDC_MINT; + const outputMint = topupAmount.mint + +const quoteResponse = await( + await fetch( + `${JUPITER_URL}/quote?inputMint=${inputMint.toBase58()}&outputMint=${outputMint.toBase58()}&amount=${toBN( + topupAmount.sourceAmount, + 6 + ).toString()}&slippageBps=50&onlyDirectRoutes=true` + ) +).json(); +if (quoteResponse.error) { + throw new Error("Failed to get quote: " + quoteResponse.error); +} +const destination = getAssociatedTokenAddressSync( + inputMint, + maker, + true +); +const instructions = await( + await fetch(`${JUPITER_URL}/swap-instructions`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + // quoteResponse from /quote api + quoteResponse, + userPublicKey: payer, + destinationTokenAccount: destination, + }), + }) +).json(); +if (instructions.error) { + throw new Error("Failed to get swap instructions: " + instructions.error); +} + +const conversionEscrow = conversionEscrowKey(usdcMint, maker)[0]; +const conversionEscrowAcc = await ceProgram.account.conversionEscrowV0.fetch(conversionEscrow); +const oracle = conversionEscrowAcc.targets.find((t) => t.mint === outputMint)?.oracle; + +const { + computeBudgetInstructions, // The necessary instructions to setup the compute budget. + swapInstruction: swapInstructionPayload, // The actual swap instruction. + addressLookupTableAddresses, // The lookup table addresses that you can use if you are using versioned transaction. +} = instructions; + +return { + instructions: [ + await program.methods + .makerLendV0() + .accounts({ + maker, + targetOracle: MOBILE_PYTH_PRICE_FEED, + conversionEscrow, + oracle, + escrow: getAssociatedTokenAddressSync( + inputMint, + conversionEscrow, + true + ), + destination: getAssociatedTokenAddressSync(inputMint, payer), + repayAccount: destination, + sourceMint: inputMint, + }) + .instruction(), + ...computeBudgetInstructions.map(deserializeInstruction), + deserializeInstruction(swapInstructionPayload), + await ceProgram.methods + .checkRepayV0() + .accounts({ + conversionEscrow, + repayAccount: destination, + }) + .instruction(), + ], + addressLookupTableAddresses: addressLookupTableAddresses.map( + (a: any) => new PublicKey(a) + ), +}; + })); +} diff --git a/packages/helium-entity-manager-sdk/src/functions/utils.ts b/packages/helium-entity-manager-sdk/src/functions/utils.ts new file mode 100644 index 000000000..37c9c0485 --- /dev/null +++ b/packages/helium-entity-manager-sdk/src/functions/utils.ts @@ -0,0 +1,13 @@ +import { PublicKey, TransactionInstruction } from "@solana/web3.js"; + +export const deserializeInstruction = (instruction: any) => { + return new TransactionInstruction({ + programId: new PublicKey(instruction.programId), + keys: instruction.accounts.map((key: any) => ({ + pubkey: new PublicKey(key.pubkey), + isSigner: key.isSigner, + isWritable: key.isWritable, + })), + data: Buffer.from(instruction.data, "base64"), + }); +}; diff --git a/packages/helium-entity-manager-sdk/src/index.ts b/packages/helium-entity-manager-sdk/src/index.ts index 2027d79af..ad5a63b80 100644 --- a/packages/helium-entity-manager-sdk/src/index.ts +++ b/packages/helium-entity-manager-sdk/src/index.ts @@ -8,6 +8,7 @@ import { HeliumEntityManager } from "@helium/idls/lib/types/helium_entity_manage export * from "./constants"; export { onboardIotHotspot } from "./functions/onboardIotHotspot"; export { onboardMobileHotspot } from "./functions/onboardMobileHotspot"; +export { topUpMaker } from "./functions/topUpMaker"; export { proofArgsAndAccounts } from "@helium/spl-utils"; export { updateIotMetadata } from "./functions/updateIotMetadata"; export { updateMobileMetadata } from "./functions/updateMobileMetadata"; diff --git a/packages/helium-entity-manager-sdk/src/pdas.ts b/packages/helium-entity-manager-sdk/src/pdas.ts index 2d3fb0b72..602a390b3 100644 --- a/packages/helium-entity-manager-sdk/src/pdas.ts +++ b/packages/helium-entity-manager-sdk/src/pdas.ts @@ -145,6 +145,44 @@ export const keyToAssetKey = ( return keyToAssetKeyRaw(dao, Buffer.from(hash, "hex"), programId); }; +export const mobileHotspotVoucherKeyRaw = ( + rewardableEntityConfig: PublicKey, + hashedEntityKey: Buffer, + programId: PublicKey = PROGRAM_ID +) => { + return PublicKey.findProgramAddressSync( + [ + Buffer.from("mobile_hotspot_voucher", "utf-8"), + rewardableEntityConfig.toBuffer(), + hashedEntityKey, + ], + programId + ); +}; + +export const mobileHotspotVoucherKey = ( + rewardableEntityConfig: PublicKey, + entityKey: Buffer | string, + encoding: BufferEncoding | "b58" = "b58", + programId: PublicKey = PROGRAM_ID +) => { + if (typeof entityKey === "string") { + if (encoding == "b58" || Address.isValid(entityKey)) { + entityKey = Buffer.from(bs58.decode(entityKey)); + } else { + entityKey = Buffer.from(entityKey, encoding); + } + } + const hash = sha256(entityKey); + + return mobileHotspotVoucherKeyRaw( + rewardableEntityConfig, + Buffer.from(hash, "hex"), + programId + ); +}; + + export const iotInfoKey = ( rewardableEntityConfig: PublicKey, entityKey: Buffer | string, diff --git a/packages/helium-entity-manager-sdk/src/resolvers.ts b/packages/helium-entity-manager-sdk/src/resolvers.ts index 951b27a60..362644e3b 100644 --- a/packages/helium-entity-manager-sdk/src/resolvers.ts +++ b/packages/helium-entity-manager-sdk/src/resolvers.ts @@ -7,11 +7,13 @@ import { } from "@helium/anchor-resolvers"; import { getAssociatedTokenAddressSync, + NATIVE_MINT, } from "@solana/spl-token"; import { PublicKey } from "@solana/web3.js"; import { init } from "./init"; -import { iotInfoKey, keyToAssetKey, mobileInfoKey, programApprovalKey } from "./pdas"; +import { iotInfoKey, keyToAssetKey, mobileHotspotVoucherKey, mobileInfoKey, programApprovalKey } from "./pdas"; import { notEmittedKey } from "@helium/no-emit-sdk"; +import { Accounts } from "@coral-xyz/anchor"; export const heliumEntityManagerResolvers = combineResolvers( heliumCommonResolver, @@ -53,15 +55,16 @@ export const heliumEntityManagerResolvers = combineResolvers( } }), resolveIndividual(async ({ idlIx, path, args, accounts }) => { + const dao = accounts.dao || (accounts.issueEntityCommon as Accounts)?.dao; if ( path[path.length - 1] === "keyToAsset" && args[args.length - 1] && args[args.length - 1].entityKey && - accounts.dao + dao ) { return ( await keyToAssetKey( - accounts.dao as PublicKey, + dao as PublicKey, args[args.length - 1].entityKey, args[args.length - 1].encoding || "b58" ) @@ -88,12 +91,22 @@ export const heliumEntityManagerResolvers = combineResolvers( Buffer.from("not_emitted", "utf8") ) )[0]; + } else if ( + path[path.length - 1] === "mobileHotspotVoucher" && + accounts.rewardableEntityConfig + ) { + return ( + await mobileHotspotVoucherKey( + accounts.rewardableEntityConfig as PublicKey, + args[args.length - 1].entityKey, + args[args.length - 1].keySerialization || "b58" + ) + )[0]; } }), - resolveIndividual(async ({ path, args, provider, accounts, idlIx }) => { + resolveIndividual(async ({ path, provider, accounts }) => { if ( path[path.length - 1] === "iotInfo" && - args[args.length - 1].index && accounts.merkleTree && accounts.keyToAsset ) { @@ -120,21 +133,31 @@ export const heliumEntityManagerResolvers = combineResolvers( } }), resolveIndividual(async ({ path, args, provider, accounts }) => { + const merkleTree = + accounts.merkleTree || + (accounts.issueEntityCommon as Accounts)?.merkleTree; + const keyToAsset = + accounts.keyToAsset || + (accounts.issueEntityCommon as Accounts)?.keyToAsset; if ( path[path.length - 1] === "mobileInfo" && - args[args.length - 1].index && - accounts.merkleTree && + merkleTree && + keyToAsset && accounts.rewardableEntityConfig ) { - // @ts-ignore - const program = await init(provider); - const keyToAssetAcc = await program.account.keyToAssetV0.fetch( - accounts.keyToAsset as PublicKey - ); + let entityKey = args[0].entityKey; + if (!entityKey) { + // @ts-ignore + const program = await init(provider); + const keyToAssetAcc = await program.account.keyToAssetV0.fetch( + keyToAsset as PublicKey + ); + entityKey = keyToAssetAcc.entityKey; + } return ( await mobileInfoKey( accounts.rewardableEntityConfig as PublicKey, - keyToAssetAcc.entityKey + entityKey ) )[0]; } @@ -163,6 +186,12 @@ export const heliumEntityManagerResolvers = combineResolvers( mint: "hotspot", owner: "hotspotOwner", }), + ataResolver({ + instruction: "mobileVoucherPayDcV0", + mint: "dcMint", + account: "dcBurner", + owner: "maker", + }), ataResolver({ account: "dcBurner", mint: "dcMint", @@ -180,6 +209,36 @@ export const heliumEntityManagerResolvers = combineResolvers( account: "dntBurner", owner: "payer", }), + ataResolver({ + instruction: "mobileVoucherPayMobileV0", + mint: "dntMint", + account: "dntBurner", + owner: "maker", + }), + ataResolver({ + instruction: "initializeMakerEscrowV0", + mint: "mint", + account: "escrow", + owner: "conversionEscrow", + }), + ataResolver({ + instruction: "payMobileVoucherV0", + mint: "hntMint", + account: "hntBurner", + owner: "maker", + }), + ataResolver({ + instruction: "payMobileVoucherV0", + mint: "dcMint", + account: "dcBurner", + owner: "maker", + }), + ataResolver({ + instruction: "payMobileVoucherV0", + mint: "dntMint", + account: "dntBurner", + owner: "maker", + }), ataResolver({ instruction: "onboardDataOnlyMobileHotspotV0", mint: "dntMint", @@ -188,3 +247,11 @@ export const heliumEntityManagerResolvers = combineResolvers( }), subDaoEpochInfoResolver ); + +function getParent(accounts: any, path: string[]) { + let parent = accounts; + for (let i = 0; i < path.length - 1; i++) { + parent = parent[path[i]]; + } + return parent; +} diff --git a/packages/helium-entity-manager-sdk/tsconfig.json b/packages/helium-entity-manager-sdk/tsconfig.json index 5f0316873..9d229cf07 100644 --- a/packages/helium-entity-manager-sdk/tsconfig.json +++ b/packages/helium-entity-manager-sdk/tsconfig.json @@ -13,6 +13,9 @@ { "path": "../helium-sub-daos-sdk" }, + { + "path": "../conversion-escrow-sdk" + }, { "path": "../no-emit-sdk" }, diff --git a/packages/spl-utils/src/constants.ts b/packages/spl-utils/src/constants.ts index ac194f25d..4114e3065 100644 --- a/packages/spl-utils/src/constants.ts +++ b/packages/spl-utils/src/constants.ts @@ -12,11 +12,24 @@ export const MOBILE_MINT = new PublicKey( export const IOT_MINT = new PublicKey("iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns"); -// TODO: Replace with actual HNT feed export const HNT_PYTH_PRICE_FEED = new PublicKey( "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33" ); +export const SOL_PYTH_PRICE_FEED = new PublicKey( + "7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE" +); + +export const MOBILE_PYTH_PRICE_FEED = new PublicKey( + "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx" +); + +export const USDC_PYTH_PRICE_FEED = new PublicKey( + "Dpw1EAVrSB1ibxiDQyTAW6Zip3J4Btk2x4SgApQCeFbX" +); + +export const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); + export const HELIUM_COMMON_LUT_DEVNET = new PublicKey( "FnqYkQ6ZKnVKdkvYCGsEeiP5qgGqVbcFUkGduy2ta4gA" ); @@ -36,4 +49,98 @@ export const realmNames: Record = { [HNT_MINT.toBase58()]: "Helium", [MOBILE_MINT.toBase58()]: "Helium MOBILE", [IOT_MINT.toBase58()]: "Helium IOT", -}; \ No newline at end of file +}; + +export const LUT_ACCOUNTS = [ + // Programs + "1azyuavdMyvsivtNxPoz6SucD18eDHeXzFCUPq5XU7w", + "hdaoVTCqhfHHo75XdAMxBKdUqvq1i5bF23sisBqVgGR", + "credMBJhYFzfn7NxBMdU4aUqFggAjgztaCcv2Fo6fPT", + "hemjuPXBpNvggtaUnN1MwT3wrdhttKEfosTcc2P9Pg8", + "circAbx64bbsscPbQzZAUvuXpHqrCe6fLMzc2uKXz9g", + "treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5", + "1atrmQs3eq1N2FEYWu6tyTXbCjP4uQwExpjtnhXtS8h", + "porcSnvH9pvcYPmQ65Y8qcZSRxQBiBBQX7UV5nmBegy", + "rorcfdX4h9m9swCKgcypaHJ8NGYVANBpmV9EHn3cYrF", + "hvsrNC3NKbcryqDs2DocYHZ9yPKEVzdSjQG6RVtK1s8", + "fanqeMu3fw8R4LwKNbahPtYXJsyLL6NXyfe2BqzhfB6", + "memMa1HG4odAFmUbGWfPwS1WWfK95k99F2YTkGvyxZr", + "hexbnKYoA2GercNNhHUCCfrTRWrHjT6ujKPXTa5NPqJ", + "noEmmgLmQdk6DLiPV8CSwQv3qQDyGEhz9m5A4zhtByv", + "cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w", + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "11111111111111111111111111111111", + // Lazy distributor IOT + "37eiz5KzYwpAdLgrSh8GT1isKiJ6hcE5ET86dqaoCugL", + // Lazy dist Oracle + "orc1TYY5L4B4ZWDEMayTqu99ikPM9bQo9fqzoaCPP5Q", + // Oracle signer + "7WuVr8SGcZ4KxpHBEdRGVTeSwkhk1WGUXT7DEzvWpYu4", + // Lazy dist mobile + "GZtTp3AUo2AHdQe9BCJ6gXR9KqfruRvHnZ4QiJUALMcz", + // Hnt pyth + "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33", + // Mobile pyth + "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx", + // Usdc pyth + "Dpw1EAVrSB1ibxiDQyTAW6Zip3J4Btk2x4SgApQCeFbX", + // Hnt + "hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux", + // dc + "dcuc8Amr83Wz27ZkQ2K9NS6r8zRpf1J6cvArEBDZDmm", + // Mobile + "mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6", + // Dao + "BQ3MCuTT5zVBhNfQ4SjMh3NPVhFy73MPV8rjfq5d1zie", + // Mobile subdao + "Gm9xDCJawDEKDrrQW6haw94gABaYzQwCq4ZQU8h8bd22", + // Iot subdao + "39Lw1RH6zt8AJvKn3BTxmUDofzduCM2J3kSaGDZ8L7Sk", + // Mobile Delegator pool + "71Y96vbVWYkoVQUgVsd8LSBRRDrgp5pf1sKznM5KuaA7", + // Mobile Delegator pool circuit breaker + "2cocTPZ7aRT62wTDGkosF98oo4iqCtkZnFdNHWqNZLuS", + // Iot delegator pool + "6fvj6rSwTeCkY7i45jYZYpZEhKmPRSTmA29hUDiMSFtU", + // Iot delegator pool circuit breaker + "6mNUqFAyLBkV88Nj6ctrcv66iJMHwzNzV8XFUwLmGerG", + // Mobile rewardable entity config + "EP1FNydbuKjGopwXVrVLR71NnC9YMRbTg9aHfk3KfMRj", + // Compression proram + "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK", + // Mobile escrow circuit breaker + "4qGj88CX3McdTXEviEaqeP2pnZJxRTsZFWyU3Mrnbku4", + // Mobile escrow + "GD37bnQdGkDsjNqnVGr9qWTnQJSKMHbsiXX9tXLMUcaL", + // Iot escrow + "4po3YMfioHkNP4mL4N46UWJvBoQDS2HFjzGm1ifrUWuZ", + // Iot escrow circuit breaker + "5veMSa4ks66zydSaKSPMhV7H2eF88HvuKDArScNH9jaG", + // Hnt registrar + "BMnWRWZrWqb6JMKznaDqNxWaWAHoaTzVabM6Qwyh3WKz", + // Data credits + "D1LbvrJQ9K2WbGPMbM3Fnrf5PSsDH1TDpjqJdHuvs81n", + // HNT Proposal Config + "22SWTDZVj1L81SXfwbEeUmdZBFj23MFmER3Gv8BmxbBS", + // HNT state controller + "7Vrme34DXPH8ow4HEAatZKwZF9AR5vq8MZhA3CanMEbr", + // IOT proposal config + "7cvYwyj6k4NEPNoaCTUufDdGJqqB6ZBRf4t3TrSSUGrc", + // IOT State controller + "3eEnmZBiJems6ipPtdQS2UkJYfPqzvnDzhWQuTTN2ou5", + // IOT Registrar + "7ZZopN1mx6ECcb3YCG8dbxeLpA44xq4gzA1ETEiaLoeL", + // State controller program + "stcfiqW3fwD9QCd8Bqr1NBLrs7dftZHBQe7RiMMA4aM", + // Mobile proposal config + "5c9JxRCj4CwhZwaUyjvpb4JJbKW7xpvEFq3Rb2upkytc", + // Mobile registrar + "C4DWaps9bLiqy4e81wJ7VTQ6QR7C4MWvwsei3ZjsaDuW", + // Mobile state controller + "r11HAkEaPqkFHwDVewcmWSfRrMaLYcBLGquC2RBn3Xp", + // Instructions sysvar + "Sysvar1nstructions1111111111111111111111111", +].map((a) => { + return new PublicKey(a); +}); diff --git a/packages/spl-utils/src/token.ts b/packages/spl-utils/src/token.ts index 371797d53..932d24dd1 100644 --- a/packages/spl-utils/src/token.ts +++ b/packages/spl-utils/src/token.ts @@ -38,7 +38,9 @@ export async function mintTo( ) ); try { - await provider.sendAndConfirm(mintTx); + await provider.sendAndConfirm(mintTx, [], { + skipPreflight: true, + }); } catch (e: any) { console.log("Error", e, e.logs); if (e.logs) { diff --git a/programs/conversion-escrow/Cargo.toml b/programs/conversion-escrow/Cargo.toml new file mode 100644 index 000000000..c73a2d728 --- /dev/null +++ b/programs/conversion-escrow/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "conversion-escrow" +version = "0.0.1" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "conversion_escrow" + +[features] +devnet = [] +no-genesis = [] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[profile.release] +overflow-checks = true + +[dependencies] +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } +spl-token = "3.5.0" +shared-utils = { workspace = true } +solana-security-txt = { workspace = true } +default-env = { workspace = true } +pyth-solana-receiver-sdk = "0.3.0" diff --git a/programs/conversion-escrow/Xargo.toml b/programs/conversion-escrow/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/programs/conversion-escrow/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/programs/conversion-escrow/src/errors.rs b/programs/conversion-escrow/src/errors.rs new file mode 100644 index 000000000..144887951 --- /dev/null +++ b/programs/conversion-escrow/src/errors.rs @@ -0,0 +1,18 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum ErrorCode { + #[msg("Error loading Pyth data")] + PythError, + BadInstructionsAccount, + ProgramMismatch, + UnknownInstruction, + #[msg("Incorrect repayment destination")] + IncorrectDestination, + MissingRepay, + InsufficientRepayAmount, + PythPriceNotFound, + ArithmeticError, + IncorrectRepaymentMint, + IncorrectRepaymentOwner, +} diff --git a/programs/conversion-escrow/src/instructions/check_repay_v0.rs b/programs/conversion-escrow/src/instructions/check_repay_v0.rs new file mode 100644 index 000000000..b8e2da782 --- /dev/null +++ b/programs/conversion-escrow/src/instructions/check_repay_v0.rs @@ -0,0 +1,20 @@ +use crate::{errors::ErrorCode, ConversionEscrowV0}; +use anchor_lang::prelude::*; +use anchor_spl::token::TokenAccount; + +#[derive(Accounts)] +pub struct CheckRepayV0<'info> { + pub conversion_escrow: Account<'info, ConversionEscrowV0>, + /// CHECK: This is checked by lend_v0 as the second account + pub repay_account: Box>, +} + +pub fn handler(ctx: Context) -> Result<()> { + require_gte!( + ctx.accounts.repay_account.amount, + ctx.accounts.conversion_escrow.temp_expected_repay + + ctx.accounts.conversion_escrow.temp_repay_balance, + ErrorCode::InsufficientRepayAmount + ); + Ok(()) +} diff --git a/programs/conversion-escrow/src/instructions/initialize_escrow_v0.rs b/programs/conversion-escrow/src/instructions/initialize_escrow_v0.rs new file mode 100644 index 000000000..926ab435c --- /dev/null +++ b/programs/conversion-escrow/src/instructions/initialize_escrow_v0.rs @@ -0,0 +1,80 @@ +use crate::ConversionTargetV0; +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::AssociatedToken, + token::{Mint, Token, TokenAccount}, +}; + +use crate::ConversionEscrowV0; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct InitializeEscrowArgsV0 { + pub oracle: Pubkey, + pub targets: Vec, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct ConversionTargetArgV0 { + pub mint: Pubkey, + pub oracle: Pubkey, + /// How much slippage to allow from the oracle price + pub slippage_bps: u16, +} + +#[derive(Accounts)] +#[instruction(args: InitializeEscrowArgsV0)] +pub struct InitializeEscrowV0<'info> { + #[account(mut)] + pub payer: Signer<'info>, + /// CHECK: The owner of this account. Can fully withdraw + pub owner: Signer<'info>, + /// CHECK: The update authority + pub update_authority: AccountInfo<'info>, + #[account( + init, + payer = payer, + seeds = [b"conversion_escrow", mint.key().as_ref(), owner.key().as_ref()], + bump, + space = std::mem::size_of::() + 60 + std::mem::size_of::() * args.targets.len(), + )] + pub conversion_escrow: Box>, + pub mint: Box>, + #[account( + init, + payer = payer, + associated_token::authority = conversion_escrow, + associated_token::mint = mint + )] + pub escrow: Box>, + pub system_program: Program<'info, System>, + pub associated_token_program: Program<'info, AssociatedToken>, + pub token_program: Program<'info, Token>, +} + +pub fn handler(ctx: Context, args: InitializeEscrowArgsV0) -> Result<()> { + ctx + .accounts + .conversion_escrow + .set_inner(ConversionEscrowV0 { + oracle: args.oracle, + escrow: ctx.accounts.escrow.key(), + mint: ctx.accounts.mint.key(), + targets: args + .targets + .iter() + .map(|t| ConversionTargetV0 { + reserved: [0; 8], + mint: t.mint, + oracle: t.oracle, + slippage_bps: t.slippage_bps, + }) + .collect(), + owner: ctx.accounts.owner.key(), + update_authority: ctx.accounts.update_authority.key(), + bump_seed: ctx.bumps["conversion_escrow"], + temp_repay_balance: 0, + temp_expected_repay: 0, + }); + + Ok(()) +} diff --git a/programs/conversion-escrow/src/instructions/lend_v0.rs b/programs/conversion-escrow/src/instructions/lend_v0.rs new file mode 100644 index 000000000..0c08c7da7 --- /dev/null +++ b/programs/conversion-escrow/src/instructions/lend_v0.rs @@ -0,0 +1,191 @@ +use std::cmp::Ordering; + +use anchor_lang::{ + prelude::*, + solana_program::{ + sysvar, + sysvar::instructions::{load_current_index_checked, load_instruction_at_checked}, + }, +}; +use anchor_spl::token::{transfer, Mint, Token, TokenAccount, Transfer}; +use pyth_solana_receiver_sdk::price_update::PriceUpdateV2; + +use crate::{errors::ErrorCode, escrow_seeds, ConversionEscrowV0}; + +pub const TESTING: bool = std::option_env!("TESTING").is_some(); + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct LendArgsV0 { + pub amount: u64, +} + +#[derive(Accounts)] +pub struct LendV0<'info> { + #[account( + mut, + has_one = mint, + has_one = oracle, + has_one = escrow, + has_one = owner, + )] + pub conversion_escrow: Box>, + pub owner: Signer<'info>, + #[account(mut)] + pub escrow: Account<'info, TokenAccount>, + /// CHECK: Checked via pyth + pub oracle: Account<'info, PriceUpdateV2>, + /// CHECK: Checked via pyth + #[account( + constraint = conversion_escrow.targets.iter().any(|t| t.oracle == target_oracle.key()) + )] + pub target_oracle: Account<'info, PriceUpdateV2>, + pub mint: Box>, + + #[account( + mut, + token::mint = mint + )] + pub destination: Box>, + #[account( + constraint = conversion_escrow.targets.iter().find(|t| t.oracle == target_oracle.key()).unwrap().mint == repay_account.mint @ ErrorCode::IncorrectRepaymentMint, + constraint = repay_account.owner == conversion_escrow.owner @ ErrorCode::IncorrectRepaymentOwner + )] + pub repay_account: Box>, + /// CHECK: check instructions account + #[account(address = sysvar::instructions::ID @ErrorCode::BadInstructionsAccount)] + pub instructions: UncheckedAccount<'info>, + pub token_program: Program<'info, Token>, +} + +pub fn handler(ctx: Context, args: LendArgsV0) -> Result<()> { + let ixs = ctx.accounts.instructions.to_account_info(); + + let price_feed = &mut ctx.accounts.oracle; + let message = price_feed.price_message; + + let current_time = Clock::get()?.unix_timestamp; + require_gte!( + message + .publish_time + .saturating_add(if TESTING { 6000000 } else { 10 * 60 }.into()), + current_time, + ErrorCode::PythPriceNotFound + ); + let source_price = message.ema_price; + // Remove the confidence from the price to use the most conservative price + // https://docs.pyth.network/price-feeds/solana-price-feeds/best-practices#confidence-intervals + let source_price_with_conf = u64::try_from(source_price) + .unwrap() + .checked_sub(message.ema_conf.checked_mul(2).unwrap()) + .unwrap(); + + require_gt!(source_price_with_conf, 0); + + let target_price_oracle = &mut ctx.accounts.target_oracle; + let target_message = target_price_oracle.price_message; + + let target_price = target_message.ema_price; + require_gte!( + target_message + .publish_time + .saturating_add(if TESTING { 6000000 } else { 10 * 60 }.into()), + current_time, + ErrorCode::PythPriceNotFound + ); + + require_gt!(target_price, 0); + + // Remove the confidence from the price to use the most conservative price + // https://docs.pyth.network/price-feeds/solana-price-feeds/best-practices#confidence-intervals + let target_price_with_conf = u64::try_from(target_price) + .unwrap() + .checked_sub(target_message.ema_conf.checked_mul(2).unwrap()) + .unwrap(); + + // USD/Sorce divided by USD/Target gets us Target/Source, in other words how much target + // we expect to be repaid per source. + let target_per_source = source_price_with_conf + .checked_div(target_price_with_conf) + .unwrap(); + let expo_diff = message.exponent - target_message.exponent; + let expected_repayment_amount = match expo_diff.cmp(&0) { + Ordering::Greater => args + .amount + .checked_mul(10_u64.pow(u32::try_from(expo_diff.abs()).unwrap())) + .unwrap() + .checked_mul(target_per_source) + .unwrap(), + Ordering::Less => args + .amount + .checked_mul(target_per_source) + .unwrap() + .checked_div(10_u64.pow(u32::try_from(expo_diff.abs()).unwrap())) + .unwrap(), + Ordering::Equal => args.amount.checked_mul(target_per_source).unwrap(), + }; + let target = ctx + .accounts + .conversion_escrow + .targets + .iter() + .find(|target| target.oracle == ctx.accounts.target_oracle.key()) + .unwrap(); + let expected_repayment_amount_with_slippage = expected_repayment_amount + - (expected_repayment_amount + .checked_mul(u64::from(target.slippage_bps)) + .unwrap() + .checked_div(10000) + .unwrap()); + + // Accounting for multiple flash loans in the same tx, just need to up the expected repay. Only set initial + // balance once. + if ctx.accounts.conversion_escrow.temp_repay_balance == 0 { + ctx.accounts.conversion_escrow.temp_repay_balance = ctx.accounts.repay_account.amount; + } + ctx.accounts.conversion_escrow.temp_expected_repay += expected_repayment_amount_with_slippage; + + let current_index = load_current_index_checked(&ixs)? as usize; + // Search for the repayment instruction that should follow this lend instruction + let repay_function_hash = get_function_hash("global", "check_repay_v0"); + + // Start checking from the next instruction (skipping the current lend instruction) + for index in (current_index + 1).. { + match load_instruction_at_checked(index, &ixs) { + Ok(ix) => { + // Check if this is our repayment instruction + if ix.program_id == crate::id() + && ix.data[0..8] == repay_function_hash + && ix.accounts[0].pubkey == ctx.accounts.conversion_escrow.key() + && ix.accounts[1].pubkey == ctx.accounts.repay_account.key() + { + break; + } + } + Err(_) => return Err(ErrorCode::MissingRepay.into()), + } + } + + // Send the loan + transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.escrow.to_account_info(), + to: ctx.accounts.destination.to_account_info(), + authority: ctx.accounts.conversion_escrow.to_account_info(), + }, + &[escrow_seeds!(ctx.accounts.conversion_escrow)], + ), + args.amount, + )?; + + Ok(()) +} + +pub fn get_function_hash(namespace: &str, name: &str) -> [u8; 8] { + let preimage = format!("{}:{}", namespace, name); + let mut sighash = [0u8; 8]; + sighash + .copy_from_slice(&anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8]); + sighash +} diff --git a/programs/conversion-escrow/src/instructions/mod.rs b/programs/conversion-escrow/src/instructions/mod.rs new file mode 100644 index 000000000..81fe51a04 --- /dev/null +++ b/programs/conversion-escrow/src/instructions/mod.rs @@ -0,0 +1,7 @@ +pub mod check_repay_v0; +pub mod initialize_escrow_v0; +pub mod lend_v0; + +pub use check_repay_v0::*; +pub use initialize_escrow_v0::*; +pub use lend_v0::*; diff --git a/programs/conversion-escrow/src/lib.rs b/programs/conversion-escrow/src/lib.rs new file mode 100644 index 000000000..f27e2c5ee --- /dev/null +++ b/programs/conversion-escrow/src/lib.rs @@ -0,0 +1,49 @@ +use anchor_lang::prelude::*; +#[cfg(not(feature = "no-entrypoint"))] +use {default_env::default_env, solana_security_txt::security_txt}; + +declare_id!("cnvEguKeWyyWnKxoQ9HwrzEVfztqKjwNmerDvxdHK9w"); + +pub mod errors; +pub mod instructions; +pub mod state; + +pub use instructions::*; +pub use state::*; + +#[cfg(not(feature = "no-entrypoint"))] +security_txt! { + name: "Conversion Escrow", + project_url: "http://helium.com", + contacts: "email:hello@helium.foundation", + policy: "https://github.com/helium/helium-program-library/tree/master/SECURITY.md", + + + // Optional Fields + preferred_languages: "en", + source_code: "https://github.com/helium/helium-program-library/tree/master/programs/conversion-escrow", + source_revision: default_env!("GITHUB_SHA", ""), + source_release: default_env!("GITHUB_REF_NAME", ""), + auditors: "Sec3" +} + +#[program] +pub mod conversion_escrow { + use super::*; + + pub fn initialize_escrow_v0( + ctx: Context, + args: InitializeEscrowArgsV0, + ) -> Result<()> { + instructions::initialize_escrow_v0::handler(ctx, args) + } + + /// Lends funds to the lendee, assuming they repay in enough data credits to `owner` DC account + pub fn lend_v0(ctx: Context, args: LendArgsV0) -> Result<()> { + instructions::lend_v0::handler(ctx, args) + } + + pub fn check_repay_v0(ctx: Context) -> Result<()> { + instructions::check_repay_v0::handler(ctx) + } +} diff --git a/programs/conversion-escrow/src/state.rs b/programs/conversion-escrow/src/state.rs new file mode 100644 index 000000000..88509a4b7 --- /dev/null +++ b/programs/conversion-escrow/src/state.rs @@ -0,0 +1,38 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(Default)] +pub struct ConversionEscrowV0 { + pub escrow: Pubkey, + pub mint: Pubkey, + pub oracle: Pubkey, + pub owner: Pubkey, + pub update_authority: Pubkey, + pub targets: Vec, + /// Temporarily records the balance of the repay account to check if it has been repaid + pub temp_repay_balance: u64, + /// Temporarily records the amount we expect to be repaid + pub temp_expected_repay: u64, + pub bump_seed: u8, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct ConversionTargetV0 { + pub mint: Pubkey, + pub oracle: Pubkey, + /// How much slippage to allow from the oracle price + pub slippage_bps: u16, + pub reserved: [u64; 8], +} + +#[macro_export] +macro_rules! escrow_seeds { + ( $escrow:expr ) => { + &[ + "conversion_escrow".as_bytes(), + $escrow.mint.as_ref(), + $escrow.owner.as_ref(), + &[$escrow.bump_seed], + ] + }; +} diff --git a/programs/helium-entity-manager/Cargo.toml b/programs/helium-entity-manager/Cargo.toml index 62822b3da..4a56fe23c 100644 --- a/programs/helium-entity-manager/Cargo.toml +++ b/programs/helium-entity-manager/Cargo.toml @@ -36,3 +36,6 @@ solana-security-txt = { workspace = true } default-env = { workspace = true } no-emit = { workspace = true } pyth-solana-receiver-sdk = "0.3.0" +conversion-escrow = { path = "../conversion-escrow", features = ["cpi"] } +circuit-breaker = { workspace = true } +pyth-sdk-solana = { version = "0.8.0" } diff --git a/programs/helium-entity-manager/src/error.rs b/programs/helium-entity-manager/src/error.rs index cd4de7636..46f089b02 100644 --- a/programs/helium-entity-manager/src/error.rs +++ b/programs/helium-entity-manager/src/error.rs @@ -56,4 +56,15 @@ pub enum ErrorCode { #[msg("Arithmetic error")] ArithmeticError, + + #[msg("Cannot accept a maker loan without an onboard")] + MissingOnboard, + + #[msg("Too much was borrowed from the maker for this txn")] + TooMuchBorrowed, + + #[msg("Voucher was not paid for")] + VoucherNotPaid, + #[msg("Cannot do more than one maker lend at a time")] + LoanInProgress, } diff --git a/programs/helium-entity-manager/src/instructions/initialize_maker_escrow_v0.rs b/programs/helium-entity-manager/src/instructions/initialize_maker_escrow_v0.rs new file mode 100644 index 000000000..e465d81f1 --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/initialize_maker_escrow_v0.rs @@ -0,0 +1,91 @@ +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::AssociatedToken, + token::{Mint, Token, TokenAccount}, +}; +use conversion_escrow::{ + cpi::{accounts::InitializeEscrowV0, initialize_escrow_v0}, + program::ConversionEscrow, + ConversionTargetArgV0, InitializeEscrowArgsV0, +}; + +use crate::{maker_seeds, MakerV0}; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct InitializeMakerEscrowArgsV0 { + pub oracle: Pubkey, + pub targets: Vec, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct MConversionTargetArgV0 { + pub mint: Pubkey, + pub oracle: Pubkey, + /// How much slippage to allow from the oracle price + pub slippage_bps: u16, +} + +#[derive(Accounts)] +#[instruction(args: InitializeMakerEscrowArgsV0)] +pub struct InitializeMakerEscrowV0<'info> { + #[account( + has_one = update_authority, + )] + pub maker: Account<'info, MakerV0>, + pub update_authority: Signer<'info>, + #[account(mut)] + pub payer: Signer<'info>, + /// CHECK: Checked in CPI + #[account( + mut, + seeds = [b"conversion_escrow", mint.key().as_ref(), maker.key().as_ref()], + bump, + seeds::program = conversion_escrow_program.key(), + )] + pub conversion_escrow: UncheckedAccount<'info>, + pub mint: Box>, + /// CHECK: Checked in CPI + #[account(mut)] + pub escrow: UncheckedAccount<'info>, + pub system_program: Program<'info, System>, + pub associated_token_program: Program<'info, AssociatedToken>, + pub token_program: Program<'info, Token>, + pub conversion_escrow_program: Program<'info, ConversionEscrow>, +} + +pub fn handler( + ctx: Context, + args: InitializeMakerEscrowArgsV0, +) -> Result<()> { + initialize_escrow_v0( + CpiContext::new_with_signer( + ctx.accounts.conversion_escrow_program.to_account_info(), + InitializeEscrowV0 { + payer: ctx.accounts.payer.to_account_info(), + owner: ctx.accounts.maker.to_account_info(), + update_authority: ctx.accounts.update_authority.to_account_info(), + conversion_escrow: ctx.accounts.conversion_escrow.to_account_info(), + mint: ctx.accounts.mint.to_account_info(), + escrow: ctx.accounts.escrow.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + associated_token_program: ctx.accounts.associated_token_program.to_account_info(), + token_program: ctx.accounts.token_program.to_account_info(), + }, + &[maker_seeds!(ctx.accounts.maker)], + ), + InitializeEscrowArgsV0 { + oracle: args.oracle, + targets: args + .targets + .iter() + .map(|t| ConversionTargetArgV0 { + mint: t.mint, + oracle: t.oracle, + slippage_bps: t.slippage_bps, + }) + .collect(), + }, + )?; + + Ok(()) +} diff --git a/programs/helium-entity-manager/src/instructions/initialize_maker_v0.rs b/programs/helium-entity-manager/src/instructions/initialize_maker_v0.rs index 49261272d..0f61ae981 100644 --- a/programs/helium-entity-manager/src/instructions/initialize_maker_v0.rs +++ b/programs/helium-entity-manager/src/instructions/initialize_maker_v0.rs @@ -1,5 +1,3 @@ -use crate::error::ErrorCode; -use crate::state::*; use anchor_lang::prelude::*; use anchor_spl::{ associated_token::AssociatedToken, @@ -7,10 +5,13 @@ use anchor_spl::{ }; use helium_sub_daos::DaoV0; use mpl_token_metadata::types::{CollectionDetails, DataV2}; -use shared_utils::token_metadata::{ - create_master_edition_v3, CreateMasterEditionV3, CreateMetadataAccountsV3, +use shared_utils::{ + create_metadata_accounts_v3, + token_metadata::{create_master_edition_v3, CreateMasterEditionV3, CreateMetadataAccountsV3}, + Metadata, }; -use shared_utils::{create_metadata_accounts_v3, Metadata}; + +use crate::{error::ErrorCode, state::*}; #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct InitializeMakerArgsV0 { @@ -18,6 +19,7 @@ pub struct InitializeMakerArgsV0 { pub issuing_authority: Pubkey, pub name: String, pub metadata_url: String, + pub topup_amounts: Vec, } #[derive(Accounts)] @@ -166,6 +168,7 @@ pub fn handler(ctx: Context, args: InitializeMakerArgsV0) -> bump_seed: ctx.bumps["maker"], collection_bump_seed: ctx.bumps["collection"], dao: ctx.accounts.dao.key(), + topup_amounts: args.topup_amounts, }); Ok(()) diff --git a/programs/helium-entity-manager/src/instructions/issue_entity_v0.rs b/programs/helium-entity-manager/src/instructions/issue_entity_v0.rs index 3c1ca9030..b7c57af75 100644 --- a/programs/helium-entity-manager/src/instructions/issue_entity_v0.rs +++ b/programs/helium-entity-manager/src/instructions/issue_entity_v0.rs @@ -1,11 +1,7 @@ -use std::cmp::min; -use std::str::FromStr; +use std::{cmp::min, str::FromStr}; -use crate::{constants::ENTITY_METADATA_URL, error::ErrorCode}; -use crate::{key_to_asset_seeds, state::*}; use account_compression_cpi::{program::SplAccountCompression, Noop}; -use anchor_lang::prelude::*; -use anchor_lang::solana_program::hash::hash; +use anchor_lang::{prelude::*, solana_program::hash::hash}; use anchor_spl::token::Mint; use angry_purple_tiger::AnimalName; use bubblegum_cpi::{ @@ -16,6 +12,8 @@ use bubblegum_cpi::{ }; use helium_sub_daos::DaoV0; +use crate::{constants::ENTITY_METADATA_URL, error::ErrorCode, key_to_asset_seeds, state::*}; + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct IssueEntityArgsV0 { pub entity_key: Vec, diff --git a/programs/helium-entity-manager/src/instructions/maker_lend_v0.rs b/programs/helium-entity-manager/src/instructions/maker_lend_v0.rs new file mode 100644 index 000000000..3d20ca936 --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/maker_lend_v0.rs @@ -0,0 +1,103 @@ +/// Creates a loan from the maker to whoever is onboarding, +/// but only if they are doing a valid onboarding command later on. +use std::str::FromStr; + +use anchor_lang::{ + prelude::*, + solana_program::sysvar::{self}, +}; +use anchor_spl::token::{Mint, Token}; +use conversion_escrow::{ + cpi::{accounts::LendV0, lend_v0}, + program::ConversionEscrow, + ConversionEscrowV0, LendArgsV0, +}; + +use crate::{maker_seeds, state::*}; + +#[derive(Accounts)] +pub struct MakerLendV0<'info> { + #[account(mut)] + pub maker: Box>, + pub source_mint: Box>, + /// CHECK: Checked in cpi + pub target_oracle: UncheckedAccount<'info>, + /// CHECK: Checked in cpi + #[account(mut)] + pub escrow: AccountInfo<'info>, + /// CHECK: Checked in cpi + pub oracle: AccountInfo<'info>, + /// CHECK: Doesn't matter where it goes, so long as it is repaid + #[account(mut)] + pub destination: AccountInfo<'info>, + /// CHECK: Checked in CPI + #[account(mut)] + pub repay_account: AccountInfo<'info>, + #[account( + mut, + seeds = [b"conversion_escrow", source_mint.key().as_ref(), maker.key().as_ref()], + seeds::program = conversion_escrow_program, + bump = conversion_escrow.bump_seed, + has_one = escrow, + has_one = oracle, + constraint = conversion_escrow.owner == maker.key() + )] + pub conversion_escrow: Box>, + pub conversion_escrow_program: Program<'info, ConversionEscrow>, + /// CHECK: check instructions account + #[account(address = sysvar::instructions::ID)] + pub instructions: UncheckedAccount<'info>, + pub token_program: Program<'info, Token>, +} + +pub fn handler(ctx: Context) -> Result<()> { + let seeds = maker_seeds!(ctx.accounts.maker); + + let target = ctx + .accounts + .conversion_escrow + .targets + .iter() + .find(|target| target.oracle == ctx.accounts.target_oracle.key()) + .unwrap(); + let topup_amount = ctx + .accounts + .maker + .topup_amounts + .iter() + .find(|topup| topup.mint == target.mint) + .unwrap(); + let amount_with_slippage = topup_amount.source_amount + + topup_amount.source_amount * u64::from(target.slippage_bps) / 10000; + lend_v0( + CpiContext::new_with_signer( + ctx.accounts.conversion_escrow_program.to_account_info(), + LendV0 { + owner: ctx.accounts.maker.to_account_info(), + conversion_escrow: ctx.accounts.conversion_escrow.to_account_info(), + escrow: ctx.accounts.escrow.to_account_info(), + mint: ctx.accounts.source_mint.to_account_info(), + oracle: ctx.accounts.oracle.to_account_info(), + target_oracle: ctx.accounts.target_oracle.to_account_info(), + destination: ctx.accounts.destination.to_account_info(), + repay_account: ctx.accounts.repay_account.to_account_info(), + instructions: ctx.accounts.instructions.to_account_info(), + token_program: ctx.accounts.token_program.to_account_info(), + }, + &[seeds], + ), + LendArgsV0 { + amount: amount_with_slippage, + }, + )?; + + Ok(()) +} + +pub fn get_function_hash(namespace: &str, name: &str) -> [u8; 8] { + let preimage = format!("{}:{}", namespace, name); + let mut sighash = [0u8; 8]; + sighash + .copy_from_slice(&anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8]); + sighash +} diff --git a/programs/helium-entity-manager/src/instructions/mod.rs b/programs/helium-entity-manager/src/instructions/mod.rs index 417285d6f..98008871e 100644 --- a/programs/helium-entity-manager/src/instructions/mod.rs +++ b/programs/helium-entity-manager/src/instructions/mod.rs @@ -1,6 +1,7 @@ pub mod approve_maker_v0; pub mod approve_program_v0; pub mod initialize_data_only_v0; +pub mod initialize_maker_escrow_v0; pub mod initialize_maker_v0; pub mod initialize_rewardable_entity_config_v0; pub mod issue_data_only_entity_v0; @@ -8,6 +9,7 @@ pub mod issue_entity_v0; pub mod issue_iot_operations_fund_v0; pub mod issue_not_emitted_entity_v0; pub mod issue_program_entity_v0; +pub mod maker_lend_v0; pub mod onboard_data_only_iot_hotspot_v0; pub mod onboard_data_only_mobile_hotspot_v0; pub mod onboard_iot_hotspot_v0; @@ -24,10 +26,12 @@ pub mod update_maker_tree_v0; pub mod update_maker_v0; pub mod update_mobile_info_v0; pub mod update_rewardable_entity_config_v0; +pub mod voucher; pub use approve_maker_v0::*; pub use approve_program_v0::*; pub use initialize_data_only_v0::*; +pub use initialize_maker_escrow_v0::*; pub use initialize_maker_v0::*; pub use initialize_rewardable_entity_config_v0::*; pub use issue_data_only_entity_v0::*; @@ -35,6 +39,7 @@ pub use issue_entity_v0::*; pub use issue_iot_operations_fund_v0::*; pub use issue_not_emitted_entity_v0::*; pub use issue_program_entity_v0::*; +pub use maker_lend_v0::*; pub use onboard_data_only_iot_hotspot_v0::*; pub use onboard_data_only_mobile_hotspot_v0::*; pub use onboard_iot_hotspot_v0::*; @@ -51,3 +56,4 @@ pub use update_maker_tree_v0::*; pub use update_maker_v0::*; pub use update_mobile_info_v0::*; pub use update_rewardable_entity_config_v0::*; +pub use voucher::*; diff --git a/programs/helium-entity-manager/src/instructions/voucher/initialize_mobile_hotspot_voucher_v0.rs b/programs/helium-entity-manager/src/instructions/voucher/initialize_mobile_hotspot_voucher_v0.rs new file mode 100644 index 000000000..efb4a2085 --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/voucher/initialize_mobile_hotspot_voucher_v0.rs @@ -0,0 +1,68 @@ +use anchor_lang::{prelude::*, solana_program::hash::hash}; + +use crate::state::*; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct InitializeMobileHotspotVoucherArgsV0 { + pub entity_key: Vec, + pub key_serialization: KeySerialization, + pub device_type: MobileDeviceTypeV0, +} + +#[derive(Accounts)] +#[instruction(args: InitializeMobileHotspotVoucherArgsV0)] +pub struct InitializeMobileHotspotVoucherV0<'info> { + #[account(mut)] + pub payer: Signer<'info>, + pub issuing_authority: Signer<'info>, + #[account( + constraint = rewardable_entity_config.settings.is_mobile(), + )] + pub rewardable_entity_config: Box>, + #[account( + seeds = ["maker_approval".as_bytes(), rewardable_entity_config.key().as_ref(), maker.key().as_ref()], + bump = maker_approval.bump_seed, + has_one = maker, + has_one = rewardable_entity_config, + )] + pub maker_approval: Box>, + #[account( + mut, + has_one = issuing_authority, + )] + pub maker: Box>, + #[account( + init, + payer = payer, + space = 8 + 60 + std::mem::size_of::() + args.entity_key.len(), + seeds = [ + "mobile_hotspot_voucher".as_bytes(), + rewardable_entity_config.key().as_ref(), + &hash(&args.entity_key[..]).to_bytes() + ], + bump, + )] + pub mobile_hotspot_voucher: Box>, + pub system_program: Program<'info, System>, +} + +pub fn handler( + ctx: Context, + args: InitializeMobileHotspotVoucherArgsV0, +) -> Result<()> { + ctx + .accounts + .mobile_hotspot_voucher + .set_inner(MobileHotspotVoucherV0 { + refund: ctx.accounts.payer.key(), + rewardable_entity_config: ctx.accounts.rewardable_entity_config.key(), + entity_key: args.entity_key, + bump_seed: ctx.bumps["mobile_hotspot_voucher"], + key_serialization: args.key_serialization, + device_type: args.device_type, + paid: false, + dc_paid: 0, + maker: ctx.accounts.maker.key(), + }); + Ok(()) +} diff --git a/programs/helium-entity-manager/src/instructions/voucher/issue_entity_v1.rs b/programs/helium-entity-manager/src/instructions/voucher/issue_entity_v1.rs new file mode 100644 index 000000000..21b583cea --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/voucher/issue_entity_v1.rs @@ -0,0 +1,211 @@ +use std::{cmp::min, str::FromStr}; + +use account_compression_cpi::{program::SplAccountCompression, Noop}; +use anchor_lang::{prelude::*, solana_program::hash::hash}; +use anchor_spl::token::Mint; +use angry_purple_tiger::AnimalName; +use bubblegum_cpi::{ + cpi::{accounts::MintToCollectionV1, mint_to_collection_v1}, + get_asset_id, + program::Bubblegum, + Collection, Creator, MetadataArgs, TokenProgramVersion, TokenStandard, TreeConfig, +}; +use helium_sub_daos::DaoV0; + +use crate::{ + constants::ENTITY_METADATA_URL, error::ErrorCode, key_to_asset_seeds, state::*, + IssueEntityArgsV0, ECC_VERIFIER, +}; + +#[derive(Accounts)] +#[instruction(args: IssueEntityArgsV0)] +pub struct IssueEntityV1<'info> { + #[account(mut)] + pub payer: Signer<'info>, + #[account(address = Pubkey::from_str(ECC_VERIFIER).unwrap())] + pub ecc_verifier: Signer<'info>, + #[account( + has_one = maker, + seeds = [ + "mobile_hotspot_voucher".as_bytes(), + mobile_voucher.rewardable_entity_config.as_ref(), + &hash(&args.entity_key[..]).to_bytes() + ], + bump = mobile_voucher.bump_seed, + )] + pub mobile_voucher: Box>, + pub collection: Box>, + /// CHECK: Handled by cpi + #[account( + mut, + seeds = ["metadata".as_bytes(), token_metadata_program.key().as_ref(), collection.key().as_ref()], + seeds::program = token_metadata_program.key(), + bump, + )] + pub collection_metadata: UncheckedAccount<'info>, + /// CHECK: Handled By cpi account + #[account( + seeds = ["metadata".as_bytes(), token_metadata_program.key().as_ref(), collection.key().as_ref(), "edition".as_bytes()], + seeds::program = token_metadata_program.key(), + bump, + )] + pub collection_master_edition: UncheckedAccount<'info>, + #[account( + mut, + has_one = collection, + has_one = merkle_tree, + has_one = dao, + )] + pub maker: Box>, + /// CHECK: Signs as a verified creator to make searching easier + #[account( + seeds = [b"entity_creator", dao.key().as_ref()], + bump, + )] + pub entity_creator: UncheckedAccount<'info>, + pub dao: Box>, + #[account( + init, + payer = payer, + space = 8 + std::mem::size_of::() + 1 + args.entity_key.len(), + seeds = [ + "key_to_asset".as_bytes(), + dao.key().as_ref(), + &hash(&args.entity_key[..]).to_bytes() + ], + bump + )] + pub key_to_asset: Box>, + #[account( + mut, + seeds = [merkle_tree.key().as_ref()], + seeds::program = bubblegum_program.key(), + bump, + )] + pub tree_authority: Box>, + /// CHECK: Used in cpi + pub recipient: AccountInfo<'info>, + /// CHECK: Used in cpi + #[account(mut)] + pub merkle_tree: AccountInfo<'info>, + #[account( + seeds = ["collection_cpi".as_bytes()], + seeds::program = bubblegum_program.key(), + bump, + )] + /// CHECK: Used in cpi + pub bubblegum_signer: UncheckedAccount<'info>, + + /// CHECK: Verified by constraint + #[account(address = mpl_token_metadata::ID)] + pub token_metadata_program: AccountInfo<'info>, + pub log_wrapper: Program<'info, Noop>, + pub bubblegum_program: Program<'info, Bubblegum>, + pub compression_program: Program<'info, SplAccountCompression>, + pub system_program: Program<'info, System>, +} + +impl<'info> IssueEntityV1<'info> { + fn mint_to_collection_ctx(&self) -> CpiContext<'_, '_, '_, 'info, MintToCollectionV1<'info>> { + let cpi_accounts = MintToCollectionV1 { + tree_authority: self.tree_authority.to_account_info(), + leaf_delegate: self.recipient.to_account_info(), + leaf_owner: self.recipient.to_account_info(), + merkle_tree: self.merkle_tree.to_account_info(), + payer: self.payer.to_account_info(), + tree_delegate: self.maker.to_account_info(), + log_wrapper: self.log_wrapper.to_account_info(), + compression_program: self.compression_program.to_account_info(), + system_program: self.system_program.to_account_info(), + collection_authority: self.maker.to_account_info(), + collection_authority_record_pda: self.bubblegum_program.to_account_info(), + collection_mint: self.collection.to_account_info(), + collection_metadata: self.collection_metadata.to_account_info(), + edition_account: self.collection_master_edition.to_account_info(), + bubblegum_signer: self.bubblegum_signer.to_account_info(), + token_metadata_program: self.token_metadata_program.to_account_info(), + }; + CpiContext::new(self.bubblegum_program.to_account_info(), cpi_accounts) + } +} + +pub fn handler(ctx: Context, args: IssueEntityArgsV0) -> Result<()> { + let asset_id = get_asset_id( + &ctx.accounts.merkle_tree.key(), + ctx.accounts.tree_authority.num_minted, + ); + ctx.accounts.key_to_asset.set_inner(KeyToAssetV0 { + asset: asset_id, + dao: ctx.accounts.dao.key(), + entity_key: args.entity_key.clone(), + bump_seed: ctx.bumps["key_to_asset"], + key_serialization: KeySerialization::B58, + }); + + let key_str = bs58::encode(args.entity_key).into_string(); + let animal_name: AnimalName = key_str + .parse() + .map_err(|_| error!(ErrorCode::InvalidEccCompact))?; + + let maker_seeds: &[&[&[u8]]] = &[&[ + b"maker", + ctx.accounts.maker.dao.as_ref(), + ctx.accounts.maker.name.as_bytes(), + &[ctx.accounts.maker.bump_seed], + ]]; + + let name = animal_name.to_string(); + let uri = format!( + "{}/v2/hotspot/{}", + ENTITY_METADATA_URL, + ctx.accounts.key_to_asset.key(), + ); + let metadata = MetadataArgs { + name: name[..min(name.len(), 32)].to_owned(), + symbol: String::from("HOTSPOT"), + uri, + collection: Some(Collection { + key: ctx.accounts.collection.key(), + verified: false, // Verified in cpi + }), + primary_sale_happened: true, + is_mutable: true, + edition_nonce: None, + token_standard: Some(TokenStandard::NonFungible), + uses: None, + token_program_version: TokenProgramVersion::Original, + creators: vec![ + Creator { + address: ctx.accounts.entity_creator.key(), + verified: true, + share: 100, + }, + Creator { + address: ctx.accounts.key_to_asset.key(), + verified: true, + share: 0, + }, + ], + seller_fee_basis_points: 0, + }; + let entity_creator_seeds: &[&[&[u8]]] = &[&[ + b"entity_creator", + ctx.accounts.dao.to_account_info().key.as_ref(), + &[ctx.bumps["entity_creator"]], + ]]; + let mut creator = ctx.accounts.entity_creator.to_account_info(); + creator.is_signer = true; + let mut key_to_asset_creator = ctx.accounts.key_to_asset.to_account_info(); + key_to_asset_creator.is_signer = true; + let key_to_asset_signer: &[&[u8]] = key_to_asset_seeds!(ctx.accounts.key_to_asset); + mint_to_collection_v1( + ctx + .accounts + .mint_to_collection_ctx() + .with_remaining_accounts(vec![creator, key_to_asset_creator]) + .with_signer(&[maker_seeds[0], entity_creator_seeds[0], key_to_asset_signer]), + metadata, + )?; + + Ok(()) +} diff --git a/programs/helium-entity-manager/src/instructions/voucher/mod.rs b/programs/helium-entity-manager/src/instructions/voucher/mod.rs new file mode 100644 index 000000000..8c2c185dc --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/voucher/mod.rs @@ -0,0 +1,9 @@ +pub mod initialize_mobile_hotspot_voucher_v0; +pub mod issue_entity_v1; +pub mod onboard_mobile_hotspot_v1; +pub mod pay_mobile_voucher_v0; + +pub use initialize_mobile_hotspot_voucher_v0::*; +pub use issue_entity_v1::*; +pub use onboard_mobile_hotspot_v1::*; +pub use pay_mobile_voucher_v0::*; diff --git a/programs/helium-entity-manager/src/instructions/voucher/onboard_mobile_hotspot_v1.rs b/programs/helium-entity-manager/src/instructions/voucher/onboard_mobile_hotspot_v1.rs new file mode 100644 index 000000000..51a2fac83 --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/voucher/onboard_mobile_hotspot_v1.rs @@ -0,0 +1,110 @@ +use account_compression_cpi::program::SplAccountCompression; +use anchor_lang::{prelude::*, solana_program::hash::hash}; +use bubblegum_cpi::get_asset_id; +use helium_sub_daos::DaoV0; +use shared_utils::{verify_compressed_nft, VerifyCompressedNftArgs}; + +use crate::{ + error::ErrorCode, KeyToAssetV0, MakerApprovalV0, MakerV0, MobileDeploymentInfoV0, + MobileHotspotInfoV0, MobileHotspotVoucherV0, RewardableEntityConfigV0, MOBILE_HOTSPOT_INFO_SIZE, +}; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct OnboardMobileHotspotArgsV1 { + pub data_hash: [u8; 32], + pub creator_hash: [u8; 32], + pub root: [u8; 32], + pub index: u32, + pub deployment_info: Option, +} + +#[derive(Accounts)] +#[instruction(args: OnboardMobileHotspotArgsV1)] +pub struct OnboardMobileHotspotV1<'info> { + #[account(mut)] + pub payer: Signer<'info>, + #[account(mut)] + /// CHECK: Just getting refunded + pub refund: AccountInfo<'info>, + #[account( + has_one = dao, + )] + pub maker: Box>, + #[account( + seeds = ["maker_approval".as_bytes(), rewardable_entity_config.key().as_ref(), maker.key().as_ref()], + bump = maker_approval.bump_seed, + has_one = maker, + has_one = rewardable_entity_config, + )] + pub maker_approval: Box>, + #[account( + mut, + has_one = rewardable_entity_config, + has_one = refund, + has_one = maker, + close = refund, + constraint = mobile_voucher.paid @ ErrorCode::VoucherNotPaid, + seeds = [ + "mobile_hotspot_voucher".as_bytes(), + mobile_voucher.rewardable_entity_config.as_ref(), + &hash(&key_to_asset.entity_key[..]).to_bytes() + ], + bump = mobile_voucher.bump_seed, + )] + pub mobile_voucher: Box>, + pub rewardable_entity_config: Box>, + #[account( + init, + payer = payer, + space = MOBILE_HOTSPOT_INFO_SIZE, + seeds = [ + b"mobile_info", + rewardable_entity_config.key().as_ref(), + &hash(&key_to_asset.entity_key[..]).to_bytes() + ], + bump, + )] + pub mobile_info: Box>, + pub dao: Box>, + #[account( + has_one = dao, + constraint = get_asset_id(&merkle_tree.key(), args.index.into()) == key_to_asset.asset + )] + pub key_to_asset: Box>, + /// CHECK: The merkle tree + pub merkle_tree: UncheckedAccount<'info>, + pub hotspot_owner: Signer<'info>, + pub compression_program: Program<'info, SplAccountCompression>, + pub system_program: Program<'info, System>, +} + +pub fn handler<'info>( + ctx: Context<'_, '_, '_, 'info, OnboardMobileHotspotV1<'info>>, + args: OnboardMobileHotspotArgsV1, +) -> Result<()> { + verify_compressed_nft(VerifyCompressedNftArgs { + data_hash: args.data_hash, + creator_hash: args.creator_hash, + root: args.root, + index: args.index, + compression_program: ctx.accounts.compression_program.to_account_info(), + merkle_tree: ctx.accounts.merkle_tree.to_account_info(), + owner: ctx.accounts.hotspot_owner.key(), + delegate: ctx.accounts.hotspot_owner.key(), + proof_accounts: ctx.remaining_accounts.to_vec(), + })?; + + ctx.accounts.mobile_info.set_inner(MobileHotspotInfoV0 { + asset: ctx.accounts.key_to_asset.asset, + bump_seed: ctx.bumps["mobile_info"], + location: None, + is_full_hotspot: true, + num_location_asserts: 0, + is_active: false, + dc_onboarding_fee_paid: ctx.accounts.mobile_voucher.dc_paid, + device_type: ctx.accounts.mobile_voucher.device_type, + deployment_info: args.deployment_info, + }); + + Ok(()) +} diff --git a/programs/helium-entity-manager/src/instructions/voucher/pay_mobile_voucher_v0.rs b/programs/helium-entity-manager/src/instructions/voucher/pay_mobile_voucher_v0.rs new file mode 100644 index 000000000..bdb29edb1 --- /dev/null +++ b/programs/helium-entity-manager/src/instructions/voucher/pay_mobile_voucher_v0.rs @@ -0,0 +1,291 @@ +use std::str::FromStr; + +use account_compression_cpi::program::SplAccountCompression; +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::AssociatedToken, + token::{burn, Burn, Mint, Token, TokenAccount}, +}; +use bubblegum_cpi::get_asset_id; +use circuit_breaker::{CircuitBreaker, MintWindowedCircuitBreakerV0}; +use data_credits::{ + cpi::{ + accounts::{BurnCommonV0, BurnWithoutTrackingV0, MintDataCreditsV0}, + burn_without_tracking_v0, mint_data_credits_v0, + }, + program::DataCredits, + BurnWithoutTrackingArgsV0, DataCreditsV0, MintDataCreditsArgsV0, +}; +use helium_sub_daos::{ + cpi::{accounts::TrackDcOnboardingFeesV0, track_dc_onboarding_fees_v0}, + program::HeliumSubDaos, + DaoV0, SubDaoV0, TrackDcOnboardingFeesArgsV0, +}; +use pyth_solana_receiver_sdk::price_update::PriceUpdateV2; +use shared_utils::{verify_compressed_nft, VerifyCompressedNftArgs}; + +use crate::{error::ErrorCode, maker_seeds, state::*, TESTING}; + +const PRICE_ORACLE: &str = "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx"; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct PayMobileVoucherArgsV0 { + pub data_hash: [u8; 32], + pub creator_hash: [u8; 32], + pub root: [u8; 32], + pub index: u32, +} + +#[derive(Accounts)] +#[instruction(args: PayMobileVoucherArgsV0)] +pub struct PayMobileVoucherV0<'info> { + #[account(mut)] + pub maker: Box>, + #[account(mut)] + pub payer: Signer<'info>, + #[account(mut)] + pub hotspot_owner: Signer<'info>, + #[account( + has_one = sub_dao, + constraint = rewardable_entity_config.settings.is_mobile(), + )] + pub rewardable_entity_config: Box>, + #[account( + mut, + has_one = rewardable_entity_config, + has_one = maker, + )] + pub mobile_voucher: Box>, + #[account( + mut, + has_one = dao, + has_one = dnt_mint, + )] + pub sub_dao: Box>, + #[account( + has_one = dc_mint, + has_one = hnt_mint, + )] + pub dao: Box>, + #[account(mut)] + pub dc_mint: Box>, + #[account(mut)] + pub dnt_mint: Box>, + #[account(mut)] + pub hnt_mint: Box>, + /// CHECK: Checked by loading with pyth. Also double checked by the has_one on data credits instance. + #[account( + address = Pubkey::from_str(PRICE_ORACLE).unwrap() + )] + pub dnt_price: Box>, + #[account( + seeds=[ + "dc".as_bytes(), + dc_mint.key().as_ref() + ], + seeds::program = data_credits_program.key(), + bump = dc.data_credits_bump, + has_one = dc_mint, + has_one = hnt_price_oracle, + )] + pub dc: Account<'info, DataCreditsV0>, + pub hnt_price_oracle: Box>, + #[account( + init_if_needed, + payer = payer, + associated_token::mint = hnt_mint, + associated_token::authority = maker, + )] + pub hnt_burner: Box>, + #[account( + init_if_needed, + payer = payer, + associated_token::mint = dc_mint, + associated_token::authority = maker, + )] + pub dc_burner: Box>, + #[account( + init_if_needed, + payer = payer, + associated_token::authority = maker, + associated_token::mint = dnt_mint + )] + pub dnt_burner: Account<'info, TokenAccount>, + /// CHECK: Verified by cpi + #[account( + mut, + seeds = ["mint_windowed_breaker".as_bytes(), dc_mint.key().as_ref()], + seeds::program = circuit_breaker_program.key(), + bump = circuit_breaker.bump_seed + )] + pub circuit_breaker: Box>, + #[account( + has_one = dao, + constraint = get_asset_id(&merkle_tree.key(), args.index.into()) == key_to_asset.asset, + )] + pub key_to_asset: Box>, + /// CHECK: The merkle tree + pub merkle_tree: UncheckedAccount<'info>, + pub circuit_breaker_program: Program<'info, CircuitBreaker>, + pub token_program: Program<'info, Token>, + pub data_credits_program: Program<'info, DataCredits>, + pub compression_program: Program<'info, SplAccountCompression>, + pub system_program: Program<'info, System>, + pub associated_token_program: Program<'info, AssociatedToken>, + pub helium_sub_daos_program: Program<'info, HeliumSubDaos>, +} + +pub fn handler<'info>( + ctx: Context<'_, '_, '_, 'info, PayMobileVoucherV0<'info>>, + args: PayMobileVoucherArgsV0, +) -> Result<()> { + verify_compressed_nft(VerifyCompressedNftArgs { + data_hash: args.data_hash, + creator_hash: args.creator_hash, + root: args.root, + index: args.index, + compression_program: ctx.accounts.compression_program.to_account_info(), + merkle_tree: ctx.accounts.merkle_tree.to_account_info(), + owner: ctx.accounts.hotspot_owner.key(), + delegate: ctx.accounts.hotspot_owner.key(), + proof_accounts: ctx.remaining_accounts.to_vec(), + })?; + + let fees = ctx + .accounts + .rewardable_entity_config + .settings + .mobile_device_fees(ctx.accounts.mobile_voucher.device_type) + .ok_or(error!(ErrorCode::InvalidDeviceType))?; + + let dc_fee = fees.dc_onboarding_fee; + if dc_fee > 0 { + if ctx.accounts.dc_burner.amount < dc_fee { + mint_data_credits_v0( + CpiContext::new_with_signer( + ctx.accounts.data_credits_program.to_account_info(), + MintDataCreditsV0 { + data_credits: ctx.accounts.dc.to_account_info(), + hnt_price_oracle: ctx.accounts.hnt_price_oracle.to_account_info(), + burner: ctx.accounts.hnt_burner.to_account_info(), + recipient_token_account: ctx.accounts.dc_burner.to_account_info(), + recipient: ctx.accounts.maker.to_account_info(), + owner: ctx.accounts.maker.to_account_info(), + hnt_mint: ctx.accounts.hnt_mint.to_account_info(), + dc_mint: ctx.accounts.dc_mint.to_account_info(), + circuit_breaker: ctx.accounts.circuit_breaker.to_account_info(), + circuit_breaker_program: ctx.accounts.circuit_breaker_program.to_account_info(), + token_program: ctx.accounts.token_program.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + associated_token_program: ctx.accounts.associated_token_program.to_account_info(), + }, + &[maker_seeds!(ctx.accounts.maker)], + ), + MintDataCreditsArgsV0 { + hnt_amount: None, + dc_amount: Some(dc_fee - ctx.accounts.dc_burner.amount), + }, + )?; + } + let cpi_accounts = BurnWithoutTrackingV0 { + burn_accounts: BurnCommonV0 { + data_credits: ctx.accounts.dc.to_account_info(), + burner: ctx.accounts.dc_burner.to_account_info(), + owner: ctx.accounts.maker.to_account_info(), + dc_mint: ctx.accounts.dc_mint.to_account_info(), + token_program: ctx.accounts.token_program.to_account_info(), + associated_token_program: ctx.accounts.associated_token_program.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + }, + }; + + burn_without_tracking_v0( + CpiContext::new_with_signer( + ctx.accounts.data_credits_program.to_account_info(), + cpi_accounts, + &[maker_seeds!(ctx.accounts.maker)], + ), + BurnWithoutTrackingArgsV0 { amount: dc_fee }, + )?; + track_dc_onboarding_fees_v0( + CpiContext::new_with_signer( + ctx.accounts.helium_sub_daos_program.to_account_info(), + TrackDcOnboardingFeesV0 { + hem_auth: ctx.accounts.rewardable_entity_config.to_account_info(), + sub_dao: ctx.accounts.sub_dao.to_account_info(), + }, + &[&[ + "rewardable_entity_config".as_bytes(), + ctx.accounts.sub_dao.key().as_ref(), + ctx.accounts.rewardable_entity_config.symbol.as_bytes(), + &[ctx.accounts.rewardable_entity_config.bump_seed], + ]], + ), + TrackDcOnboardingFeesArgsV0 { + amount: fees.dc_onboarding_fee, + add: true, + symbol: ctx.accounts.rewardable_entity_config.symbol.clone(), + }, + )?; + } + + let dnt_fee = fees.mobile_onboarding_fee_usd; + let mobile_price_oracle = &mut ctx.accounts.dnt_price; + let current_time = Clock::get()?.unix_timestamp; + require_gte!( + mobile_price_oracle + .price_message + .publish_time + .saturating_add(if TESTING { 6000000 } else { 10 * 60 }.into()), + current_time, + ErrorCode::PythPriceFeedStale + ); + let mobile_price = mobile_price_oracle.price_message.ema_price; + // Remove the confidence from the price to use the most conservative price + // https://docs.pyth.network/price-feeds/solana-price-feeds/best-practices#confidence-intervals + let mobile_price_with_conf = mobile_price + .checked_sub( + i64::try_from( + mobile_price_oracle + .price_message + .ema_conf + .checked_mul(2) + .unwrap(), + ) + .unwrap(), + ) + .unwrap(); + // Exponent is a negative number, likely -8 + // Since the price is multiplied by an extra 10^8, and we're dividing by that price, need to also multiply + // by the exponent + let exponent_dec = 10_u64 + .checked_pow(u32::try_from(-mobile_price_oracle.price_message.exponent).unwrap()) + .ok_or_else(|| error!(ErrorCode::ArithmeticError))?; + + require_gt!(mobile_price_with_conf, 0); + let mobile_fee = dnt_fee + .checked_mul(exponent_dec) + .unwrap() + .checked_div(mobile_price_with_conf.try_into().unwrap()) + .unwrap(); + if mobile_fee > 0 { + let signer_seeds = maker_seeds!(ctx.accounts.maker); + burn( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Burn { + mint: ctx.accounts.dnt_mint.to_account_info(), + from: ctx.accounts.dnt_burner.to_account_info(), + authority: ctx.accounts.maker.to_account_info(), + }, + &[signer_seeds], + ), + mobile_fee, + )?; + } + + ctx.accounts.mobile_voucher.paid = true; + ctx.accounts.mobile_voucher.dc_paid = dc_fee; + + Ok(()) +} diff --git a/programs/helium-entity-manager/src/lib.rs b/programs/helium-entity-manager/src/lib.rs index 34e7c5ac9..261e0b034 100644 --- a/programs/helium-entity-manager/src/lib.rs +++ b/programs/helium-entity-manager/src/lib.rs @@ -10,7 +10,6 @@ pub mod instructions; pub mod state; pub use instructions::*; - pub use state::*; #[cfg(not(feature = "no-entrypoint"))] @@ -181,10 +180,49 @@ pub mod helium_entity_manager { temp_standardize_entity::handler(ctx, args) } + pub fn maker_lend_v0<'info>(ctx: Context<'_, '_, '_, 'info, MakerLendV0<'info>>) -> Result<()> { + maker_lend_v0::handler(ctx) + } + + pub fn initialize_mobile_hotspot_voucher_v0<'info>( + ctx: Context<'_, '_, '_, 'info, InitializeMobileHotspotVoucherV0<'info>>, + args: InitializeMobileHotspotVoucherArgsV0, + ) -> Result<()> { + initialize_mobile_hotspot_voucher_v0::handler(ctx, args) + } + + pub fn initialize_maker_escrow_v0<'info>( + ctx: Context<'_, '_, '_, 'info, InitializeMakerEscrowV0<'info>>, + args: InitializeMakerEscrowArgsV0, + ) -> Result<()> { + initialize_maker_escrow_v0::handler(ctx, args) + } + + pub fn onboard_mobile_hotspot_v1<'info>( + ctx: Context<'_, '_, '_, 'info, OnboardMobileHotspotV1<'info>>, + args: OnboardMobileHotspotArgsV1, + ) -> Result<()> { + onboard_mobile_hotspot_v1::handler(ctx, args) + } + pub fn onboard_data_only_mobile_hotspot_v0<'info>( ctx: Context<'_, '_, '_, 'info, OnboardDataOnlyMobileHotspotV0<'info>>, args: OnboardDataOnlyMobileHotspotArgsV0, ) -> Result<()> { onboard_data_only_mobile_hotspot_v0::handler(ctx, args) } + + pub fn pay_mobile_voucher_v0<'info>( + ctx: Context<'_, '_, '_, 'info, PayMobileVoucherV0<'info>>, + args: PayMobileVoucherArgsV0, + ) -> Result<()> { + pay_mobile_voucher_v0::handler(ctx, args) + } + + pub fn issue_entity_v1<'info>( + ctx: Context<'_, '_, '_, 'info, IssueEntityV1<'info>>, + args: IssueEntityArgsV0, + ) -> Result<()> { + issue_entity_v1::handler(ctx, args) + } } diff --git a/programs/helium-entity-manager/src/state.rs b/programs/helium-entity-manager/src/state.rs index 29b161a72..f3a310e27 100644 --- a/programs/helium-entity-manager/src/state.rs +++ b/programs/helium-entity-manager/src/state.rs @@ -12,6 +12,21 @@ pub struct RewardableEntityConfigV0 { pub staking_requirement: u64, } +#[account] +#[derive(Default)] +pub struct MobileHotspotVoucherV0 { + pub maker: Pubkey, + pub rewardable_entity_config: Pubkey, + pub entity_key: Vec, + pub key_serialization: KeySerialization, + pub device_type: MobileDeviceTypeV0, + pub paid: bool, + pub dc_paid: u64, + /// The wallet that paid the rent for this, will be refunded + pub refund: Pubkey, + pub bump_seed: u8, +} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Default, PartialEq)] pub enum MobileDeviceTypeV0 { #[default] @@ -145,6 +160,14 @@ pub struct MakerV0 { pub merkle_tree: Pubkey, pub collection_bump_seed: u8, pub dao: Pubkey, + pub topup_amounts: Vec, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct TopupAmountV0 { + pub mint: Pubkey, + pub threshold: u64, + pub source_amount: u64, } #[account] @@ -274,6 +297,18 @@ pub const MOBILE_HOTSPOT_INFO_SIZE: usize = 8 + 2 + // azimuth 60; // pad +#[macro_export] +macro_rules! maker_seeds { + ( $maker:expr ) => { + &[ + "maker".as_bytes(), + $maker.dao.as_ref(), + $maker.name.as_bytes(), + &[$maker.bump_seed], + ] + }; +} + #[macro_export] macro_rules! data_only_config_seeds { ( $data_only_config:expr ) => { diff --git a/programs/mobile-entity-manager/src/state.rs b/programs/mobile-entity-manager/src/state.rs index af2851172..f78a2b098 100644 --- a/programs/mobile-entity-manager/src/state.rs +++ b/programs/mobile-entity-manager/src/state.rs @@ -18,6 +18,23 @@ pub struct CarrierV0 { pub incentive_escrow_fund_bps: u16, } +pub struct HotspotConfigV0 { + pub sub_dao: Pubkey, + pub staking_requirement: u64, +} + +pub struct HotspotVoucherV0 { + pub device_type: MobileDeviceTypeV0, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Default, PartialEq)] +pub enum MobileDeviceTypeV0 { + #[default] + Cbrs, + WifiIndoor, + WifiOutdoor, +} + #[macro_export] macro_rules! carrier_seeds { ( $carrier:expr ) => { diff --git a/tests/conversion-escrow.ts b/tests/conversion-escrow.ts new file mode 100644 index 000000000..e47a03aef --- /dev/null +++ b/tests/conversion-escrow.ts @@ -0,0 +1,209 @@ +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { createAtaAndMint, createMint, sendInstructions, toBN, toNumber } from "@helium/spl-utils"; +import { + PythSolanaReceiverProgram, + pythSolanaReceiverIdl, +} from "@pythnetwork/pyth-solana-receiver"; +import { + createAssociatedTokenAccountIdempotentInstruction, + createTransferInstruction, + getAssociatedTokenAddressSync +} from "@solana/spl-token"; +import { Keypair, PublicKey } from "@solana/web3.js"; +import { expect } from "chai"; +import { init } from "../packages/conversion-escrow-sdk/src"; +import { PROGRAM_ID } from "../packages/conversion-escrow-sdk/src/constants"; +import { ConversionEscrow } from "../target/types/conversion_escrow"; +import { ensureConversionEscrowIdl as ensureConversionEscrowIdl } from "./utils/fixtures"; + +describe("conversion-escrow", () => { + anchor.setProvider(anchor.AnchorProvider.local("http://127.0.0.1:8899")); + + const mobileOracle = new PublicKey( + "DQ4C1tzvu28cwo1roN1Wm6TW35sfJEjLh517k3ZeWevx" + ); + const hntOracle = new PublicKey( + "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33" + ); + let program: Program; + let pythProgram: Program; + let mobileMint: PublicKey; + let hntMint: PublicKey; + let startHntBal = 10000; + let startMobileEscrowBal = 100000000; + let hntDecimals = 8; + let mobileDecimals = 6; + const provider = anchor.getProvider() as anchor.AnchorProvider; + const me = provider.wallet.publicKey; + const hntHolder = Keypair.generate(); + + beforeEach(async () => { + pythProgram = new Program( + pythSolanaReceiverIdl, + new PublicKey("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ") + ); + program = await init( + provider, + PROGRAM_ID, + anchor.workspace.ConversionEscrow.idl + ) + // fresh start + mobileMint = await createMint(provider, mobileDecimals, me, me); + hntMint = await createMint(provider, hntDecimals, me, me); + await createAtaAndMint( + provider, + hntMint, + toBN(startHntBal, hntDecimals).toNumber(), + hntHolder.publicKey + ); + }); + + describe("with data credits and escrow", async () => { + let conversionEscrow: PublicKey | undefined; + + beforeEach(async () => { + await ensureConversionEscrowIdl(program); + + ({ + pubkeys: { conversionEscrow }, + } = await program.methods + .initializeEscrowV0({ + oracle: mobileOracle, + // Slippage can be super low since price isn't changing. + targets: [ + { + mint: hntMint, + slippageBps: 1, + oracle: hntOracle, + }, + ], + }) + .accounts({ + owner: me, + payer: me, + mint: mobileMint, + updateAuthority: me + }) + .rpcAndKeys({ skipPreflight: true })); + + // Populate the escrow + await createAtaAndMint( + provider, + mobileMint, + toBN(startMobileEscrowBal, mobileDecimals).toNumber(), + conversionEscrow + ); + }); + + it("lends MOBILE in exchange for HNT", async () => { + // Lend enough MOBILE to `hntHolder` to get 40000 DC. HNT holder + // will then burn enough HNT to get that DC into `owner` + console.log("fetching mobile price") + const priceMobile = await pythProgram.account.priceUpdateV2.fetch( + mobileOracle + ); + + const mobileFloorValue = + priceMobile.priceMessage.emaPrice + .sub(priceMobile.priceMessage.emaConf.mul(new anchor.BN(2))) + .toNumber() * + 10 ** priceMobile.priceMessage.exponent * + 10 ** 6; + + console.log("fetching hnt price"); + const priceHnt = await pythProgram.account.priceUpdateV2.fetch(hntOracle); + + const hntFloorValue = + priceHnt.priceMessage.emaPrice + .sub(priceMobile.priceMessage.emaConf.mul(new anchor.BN(2))) + .toNumber() * + 10 ** priceHnt.priceMessage.exponent * + 10 ** 6; + const hntPerMobile = mobileFloorValue / hntFloorValue + + const hntHolderMobileAta = getAssociatedTokenAddressSync( + mobileMint, + hntHolder.publicKey + ); + const hntHolderHntAta = getAssociatedTokenAddressSync( + hntMint, + hntHolder.publicKey + ); + console.log("mobile per hnt", 1 / hntPerMobile, mobileFloorValue, hntFloorValue); + const mobileAmount = new anchor.BN(5000) + const instructions = [ + createAssociatedTokenAccountIdempotentInstruction( + me, + hntHolderMobileAta, + hntHolder.publicKey, + mobileMint + ), + createAssociatedTokenAccountIdempotentInstruction( + me, + getAssociatedTokenAddressSync(hntMint, me), + me, + hntMint + ), + await program.methods + .lendV0({ + // Goal: get 5000 MOBILE worth of HNT + amount: mobileAmount, + }) + .accounts({ + conversionEscrow, + destination: hntHolderMobileAta, + targetOracle: hntOracle, + repayAccount: getAssociatedTokenAddressSync(hntMint, me), + }) + .instruction(), + createTransferInstruction( + hntHolderHntAta, + getAssociatedTokenAddressSync(hntMint, me), + hntHolder.publicKey, + BigInt(toBN(hntPerMobile * 5000, 8).toString()) + ), + await program.methods + .checkRepayV0() + .accounts({ + conversionEscrow, + repayAccount: getAssociatedTokenAddressSync(hntMint, me), + }) + .instruction(), + ]; + + await sendInstructions(provider, instructions, [hntHolder]); + + const hntAta = await getAssociatedTokenAddressSync( + hntMint, + hntHolder.publicKey + ); + const mobileAta = await getAssociatedTokenAddressSync( + mobileMint, + conversionEscrow!, + true + ); + const mobileBal = await provider.connection.getTokenAccountBalance( + mobileAta + ); + const hntBal = await provider.connection.getTokenAccountBalance(hntAta); + expect(mobileBal.value.uiAmount).to.eq( + // Ensure matching decimals amounts + toNumber( + toBN( + startMobileEscrowBal - toNumber(mobileAmount, mobileDecimals), + mobileDecimals + ), + mobileDecimals + ) + ); + expect(hntBal.value.uiAmount).to.eq( + // Ensure matching decimals amounts + toNumber( + toBN(startHntBal - 5000 * hntPerMobile, hntDecimals), + hntDecimals + ) + ); + }); + }); +}); diff --git a/tests/helium-entity-manager.ts b/tests/helium-entity-manager.ts index f5da17a01..ff1dd4338 100644 --- a/tests/helium-entity-manager.ts +++ b/tests/helium-entity-manager.ts @@ -1,21 +1,41 @@ import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; +import { init as initConversionEscrow } from "@helium/conversion-escrow-sdk"; import { Keypair as HeliumKeypair } from "@helium/crypto"; import { init as initDataCredits } from "@helium/data-credits-sdk"; import { init as initHeliumSubDaos } from "@helium/helium-sub-daos-sdk"; -import { notEmittedKey, init as initBurn } from "@helium/no-emit-sdk"; +import { init as initBurn, notEmittedKey } from "@helium/no-emit-sdk"; import { Asset, AssetProof, + HELIUM_COMMON_LUT, + HNT_PYTH_PRICE_FEED, + MOBILE_PYTH_PRICE_FEED, + SOL_PYTH_PRICE_FEED, + USDC_PYTH_PRICE_FEED, + batchInstructionsToTxsWithPriorityFee, createAtaAndMint, createMint, createMintInstructions, + populateMissingDraftInfo, proofArgsAndAccounts, + sendAndConfirmWithRetry, sendInstructions, toBN, + toVersionedTx, } from "@helium/spl-utils"; import { AddGatewayV1 } from "@helium/transactions"; -import { getAssociatedTokenAddressSync, getAccount } from "@solana/spl-token"; +import { + PythSolanaReceiverProgram, + pythSolanaReceiverIdl, +} from "@pythnetwork/pyth-solana-receiver"; +import { + NATIVE_MINT, + createTransferInstruction, + getAccount, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, +} from "@solana/spl-token"; import { ComputeBudgetProgram, Keypair, @@ -35,18 +55,19 @@ import { } from "../packages/helium-entity-manager-sdk/src"; import { DataCredits } from "../target/types/data_credits"; import { HeliumEntityManager } from "../target/types/helium_entity_manager"; -import { NoEmit } from "../target/types/no_emit"; import { HeliumSubDaos } from "../target/types/helium_sub_daos"; +import { NoEmit } from "../target/types/no_emit"; import { initTestDao, initTestSubdao } from "./utils/daos"; import { DC_FEE, + MAKER_STAKING_FEE, + ensureConversionEscrowIdl, ensureDCIdl, - ensureHSDIdl, ensureHEMIdl, + ensureHSDIdl, initTestDataCredits, initTestMaker, initTestRewardableEntityConfig, - MAKER_STAKING_FEE, } from "./utils/fixtures"; // @ts-ignore import bs58 from "bs58"; @@ -56,6 +77,11 @@ import { helium } from "@helium/proto"; // @ts-ignore import axios from "axios"; +import { + keyToAssetKey, + mobileInfoKey, + topUpMaker, +} from "@helium/helium-entity-manager-sdk"; import { MerkleTree, SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, @@ -63,14 +89,11 @@ import { } from "@solana/spl-account-compression"; import { BN } from "bn.js"; import chaiAsPromised from "chai-as-promised"; +import { init as initVsr } from "../packages/voter-stake-registry-sdk/src"; +import { ConversionEscrow } from "../target/types/conversion_escrow"; +import { VoterStakeRegistry } from "../target/types/voter_stake_registry"; import { createMockCompression } from "./utils/compression"; import { loadKeypair } from "./utils/solana"; -import { - keyToAssetKey, - mobileInfoKey, -} from "@helium/helium-entity-manager-sdk"; -import { VoterStakeRegistry } from "../target/types/voter_stake_registry"; -import { init as initVsr } from "../packages/voter-stake-registry-sdk/src"; chai.use(chaiAsPromised); @@ -78,9 +101,11 @@ describe("helium-entity-manager", () => { anchor.setProvider(anchor.AnchorProvider.local("http://127.0.0.1:8899")); let vsrProgram: Program; + let pythProgram: Program; let dcProgram: Program; let hsdProgram: Program; let hemProgram: Program; + let conversionEscrowProgram: Program; let noEmitProgram: Program; const provider = anchor.getProvider() as anchor.AnchorProvider; @@ -89,9 +114,25 @@ describe("helium-entity-manager", () => { let dao: PublicKey; let subDao: PublicKey; let dcMint: PublicKey; + let hntMint: PublicKey; + let dntMint: PublicKey; let activeDeviceAuthority: Keypair; + let topupAmounts: { + mint: PublicKey; + threshold: anchor.BN; + sourceAmount: anchor.BN; + }[]; beforeEach(async () => { + pythProgram = new Program( + pythSolanaReceiverIdl, + new PublicKey("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ") + ); + conversionEscrowProgram = await initConversionEscrow( + provider, + anchor.workspace.ConversionEscrow.programId, + anchor.workspace.ConversionEscrow.idl + ); dcProgram = await initDataCredits( provider, anchor.workspace.DataCredits.programId, @@ -127,17 +168,22 @@ describe("helium-entity-manager", () => { ); await ensureHEMIdl(hemProgram); - const dataCredits = await initTestDataCredits(dcProgram, provider); + const dataCredits = await initTestDataCredits( + dcProgram, + provider, + 100000000000 + ); dcMint = dataCredits.dcMint; - ({ dao } = await initTestDao( + ({ dao, mint: hntMint } = await initTestDao( hsdProgram, provider, 100, me, - dataCredits.dcMint + dataCredits.dcMint, + dataCredits.hntMint )); activeDeviceAuthority = Keypair.generate(); - ({ subDao } = await initTestSubdao({ + ({ subDao, mint: dntMint } = await initTestSubdao({ hsdProgram, vsrProgram, provider, @@ -147,6 +193,19 @@ describe("helium-entity-manager", () => { // Add some padding for onboards numTokens: MAKER_STAKING_FEE.mul(new BN(2)).add(new BN(100000000000)), })); + + topupAmounts = [ + { + mint: hntMint, + threshold: new BN(100000000), + sourceAmount: new BN(10000000), + }, + { + mint: dntMint, + threshold: new BN(1000000), + sourceAmount: new BN(10000000), + }, + ]; }); it("issues iot operations fund", async () => { @@ -599,7 +658,8 @@ describe("helium-entity-manager", () => { hemProgram, provider, rewardableEntityConfig, - dao + dao, + topupAmounts ); const account = await hemProgram.account.makerV0.fetch(maker); @@ -623,7 +683,8 @@ describe("helium-entity-manager", () => { hemProgram, provider, rewardableEntityConfig, - dao + dao, + topupAmounts ); const { @@ -737,10 +798,17 @@ describe("helium-entity-manager", () => { hemProgram, provider, rewardableEntityConfig, - dao + dao, + topupAmounts ); - await initTestMaker(hemProgram, provider, rewardableEntityConfig, dao); + await initTestMaker( + hemProgram, + provider, + rewardableEntityConfig, + dao, + topupAmounts + ); await dcProgram.methods .mintDataCreditsV0({ @@ -816,6 +884,262 @@ describe("helium-entity-manager", () => { await provider.connection.confirmTransaction(sig); }); + describe("with voucher", async () => { + let mobileHotspotVoucher: PublicKey | undefined; + let conversionEscrow: PublicKey | undefined; + let usdcMint: PublicKey; + const slippageBps = 5; + + beforeEach(async () => { + await ensureConversionEscrowIdl(conversionEscrowProgram); + usdcMint = await createMint(provider, 6, me, me); + + ({ + pubkeys: { conversionEscrow }, + } = await hemProgram.methods + .initializeMakerEscrowV0({ + oracle: USDC_PYTH_PRICE_FEED, + // Slippage can be super low since price isn't changing. + targets: [ + { + mint: dntMint, + slippageBps, + oracle: MOBILE_PYTH_PRICE_FEED, + }, + { + mint: hntMint, + slippageBps, + oracle: HNT_PYTH_PRICE_FEED, + }, + { + mint: NATIVE_MINT, + slippageBps, + oracle: SOL_PYTH_PRICE_FEED, + }, + ], + }) + .accounts({ + maker, + payer: me, + mint: usdcMint, + updateAuthority: makerKeypair.publicKey, + }) + .signers([makerKeypair]) + .rpcAndKeys({ skipPreflight: true })); + + // Populate the escrow + await createAtaAndMint( + provider, + usdcMint, + toBN(1000000, 6).toNumber(), + conversionEscrow + ); + + ({ + pubkeys: { mobileHotspotVoucher }, + } = await hemProgram.methods + .initializeMobileHotspotVoucherV0({ + entityKey: Buffer.from(bs58.decode(ecc)), + keySerialization: { b58: {} }, + deviceType: { wifiOutdoor: {} }, + }) + .accounts({ + maker, + rewardableEntityConfig, + issuingAuthority: makerKeypair.publicKey, + }) + .signers([makerKeypair]) + .rpcAndKeys({ skipPreflight: true })); + }); + + it("fits top ups in a transaction", async () => { + const txDrafts = await topUpMaker({ + program: hemProgram, + ceProgram: conversionEscrowProgram, + maker, + payer: me, + }); + const recentBlockhash = (await provider.connection.getLatestBlockhash()) + .blockhash; + const txs = await Promise.all( + txDrafts.map((tx) => + toVersionedTx({ + ...tx, + feePayer: me, + recentBlockhash, + }) + ) + ); + for (const tx of txs) { + const signed = await provider.wallet.signTransaction(tx); + console.log("signed", signed); + const serialized = signed.serialize(); + expect(serialized.length).to.be.lessThan(1232); + } + }); + + it("lends USDC to allow top ups", async () => { + await createAtaAndMint( + provider, + usdcMint, + toBN(1000, 6).toNumber(), + maker + ); + const myAcc = await createAtaAndMint( + provider, + usdcMint, + toBN(1, 6).toNumber(), + me + ); + const mobileAcc = getAssociatedTokenAddressSync(dntMint, me); + const preBalance = await provider.connection.getTokenAccountBalance( + myAcc + ); + const priceMobile = await pythProgram.account.priceUpdateV2.fetch( + MOBILE_PYTH_PRICE_FEED + ); + + const mobileFloorValue = + priceMobile.priceMessage.emaPrice + .sub(priceMobile.priceMessage.emaConf.mul(new anchor.BN(2))) + .toNumber() * + 10 ** priceMobile.priceMessage.exponent; + console.log("mobileFloor", mobileFloorValue); + const { instruction, pubkeys } = await hemProgram.methods + .makerLendV0() + .accounts({ + maker, + sourceMint: usdcMint, + targetOracle: MOBILE_PYTH_PRICE_FEED, + conversionEscrow, + destination: getAssociatedTokenAddressSync(usdcMint, me), + repayAccount: getAssociatedTokenAddressSync(dntMint, maker, true), + }) + .prepare(); + + const ixs = [ + instruction, + createTransferInstruction( + mobileAcc, + pubkeys.repayAccount!, + me, + BigInt(toBN(10 / mobileFloorValue, 6).toString()) + ), + await conversionEscrowProgram.methods + .checkRepayV0() + .accounts({ + conversionEscrow, + repayAccount: pubkeys.repayAccount, + }) + .instruction(), + ]; + + await sendInstructions(provider, ixs); + + const postBalance = await provider.connection.getTokenAccountBalance( + myAcc + ); + console.log( + postBalance.value.uiAmount, + preBalance.value.uiAmount! + 10 * (1 + slippageBps / 10000) + ); + expect(postBalance.value.uiAmount).to.be.eq( + preBalance.value.uiAmount! + + Number((10 * (1 + slippageBps / 10000)).toFixed(3)) + ); + }); + + it("issues a mobile hotspot", async () => { + await hemProgram.methods + .issueEntityV1({ + entityKey: Buffer.from(bs58.decode(ecc)), + }) + .preInstructions([ + ComputeBudgetProgram.setComputeUnitLimit({ units: 500000 }), + ]) + .accounts({ + maker, + recipient: hotspotOwner.publicKey, + mobileVoucher: mobileHotspotVoucher!, + dao, + eccVerifier: eccVerifier.publicKey, + }) + .signers([eccVerifier]) + .rpc({ skipPreflight: true }); + + const method = await onboardMobileHotspot({ + program: hemProgram, + assetId: hotspot, + maker, + dao, + rewardableEntityConfig, + getAssetFn, + getAssetProofFn, + deviceType: "wifiIndoor", + deploymentInfo: null, + }); + const txs = await batchInstructionsToTxsWithPriorityFee( + provider, + [ + createAssociatedTokenAccountIdempotentInstruction( + me, + getAssociatedTokenAddressSync(dntMint, maker, true), + maker, + dntMint + ), + createTransferInstruction( + getAssociatedTokenAddressSync(dntMint, me), + getAssociatedTokenAddressSync(dntMint, maker, true), + me, + toBN(1000, 8).toNumber() + ), + createAssociatedTokenAccountIdempotentInstruction( + me, + getAssociatedTokenAddressSync(hntMint, maker, true), + maker, + hntMint + ), + createTransferInstruction( + getAssociatedTokenAddressSync(hntMint, me), + getAssociatedTokenAddressSync(hntMint, maker, true), + me, + toBN(1000, 6).toNumber() + ), + ...(await method.transaction()).instructions, + ], + { + addressLookupTableAddresses: [HELIUM_COMMON_LUT], + computeScaleUp: 2, + } + ); + for (const draft of txs) { + const tx = toVersionedTx(draft); + try { + tx.sign([hotspotOwner]); + } catch (e) { + // ignore, one of these txs doesn't need hotspot owner to sign + } + await provider.wallet.signTransaction(tx); + await sendAndConfirmWithRetry( + provider.connection, + Buffer.from(tx.serialize()), + { + skipPreflight: true, + }, + "confirmed" + ); + } + + const { mobileInfo } = await method.pubkeys(); + + const mobileInfoAcc = + await hemProgram.account.mobileHotspotInfoV0.fetch(mobileInfo!); + expect(Boolean(mobileInfoAcc)).to.be.true; + const subDaoAcc = await hsdProgram.account.subDaoV0.fetch(subDao); + expect(subDaoAcc.dcOnboardingFeesPaid.toNumber()).to.be.eq(1000000); + }); + }); + it("issues a mobile hotspot", async () => { await hemProgram.methods .issueEntityV0({ @@ -1110,7 +1434,13 @@ describe("helium-entity-manager", () => { dao ); - await initTestMaker(hemProgram, provider, rewardableEntityConfig, dao); + await initTestMaker( + hemProgram, + provider, + rewardableEntityConfig, + dao, + topupAmounts + ); await dcProgram.methods .mintDataCreditsV0({ diff --git a/tests/utils/fixtures.ts b/tests/utils/fixtures.ts index c02dcc295..17e83f8b6 100644 --- a/tests/utils/fixtures.ts +++ b/tests/utils/fixtures.ts @@ -23,8 +23,11 @@ import { HeliumSubDaos } from "../../target/types/helium_sub_daos"; import { LazyDistributor } from "../../target/types/lazy_distributor"; import { initTestDao, initTestSubdao } from "./daos"; import { random } from "./string"; +import { ConversionEscrow } from "../../target/types/conversion_escrow"; import { PositionVotingRewards } from "../../target/types/position_voting_rewards"; +const ANCHOR_PATH = process.env.ANCHOR_PATH || 'anchor' + // TODO: replace this with helium default uri once uploaded const DEFAULT_METADATA_URL = "https://c3zu2nc2m4x6zvqf5lofrtdbsa4niuh6drvzi7lq4n465ykbd3fa.arweave.net/FvNNNFpnL-zWBercWMxhkDjUUP4ca5R9cON57uFBHso/"; @@ -120,7 +123,12 @@ export const initTestMaker = async ( program: Program, provider: anchor.AnchorProvider, rewardableEntityConfig: PublicKey, - dao: PublicKey + dao: PublicKey, + topupAmounts: { + mint: PublicKey; + threshold: anchor.BN; + sourceAmount: anchor.BN; + }[] = [] ): Promise<{ authority: PublicKey; makerKeypair: Keypair; @@ -154,6 +162,7 @@ export const initTestMaker = async ( issuingAuthority: makerKeypair.publicKey, name, metadataUrl: DEFAULT_METADATA_URL, + topupAmounts, }) .accounts({ dao, @@ -214,8 +223,6 @@ export const initTestMaker = async ( }; }; -const ANCHOR_PATH = process.env.ANCHOR_PATH || "anchor"; - export async function ensureDCIdl(dcProgram: Program) { try { execSync( @@ -300,6 +307,20 @@ export async function ensureHSDIdl(hsdProgram: Program) { } } +export async function ensureConversionEscrowIdl(dcEscrowProgram: Program) { + try { + execSync( + `${ANCHOR_PATH} idl init --filepath ${__dirname}/../../target/idl/conversion_escrow.json ${dcEscrowProgram.programId}`, + { stdio: "inherit", shell: "/bin/bash" } + ); + } catch { + execSync( + `${ANCHOR_PATH} idl upgrade --filepath ${__dirname}/../../target/idl/conversion_escrow.json ${dcEscrowProgram.programId}`, + { stdio: "inherit", shell: "/bin/bash" } + ); + } +} + export async function ensureVSRIdl(vsrProgram: Program) { try { execSync( diff --git a/tsconfig.json b/tsconfig.json index 12d281482..592c03a11 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,9 @@ { "path": "./packages/sus" }, + { + "path": "./packages/conversion-escrow-sdk" + }, { "path": "./packages/hexboosting-sdk" }, diff --git a/yarn.lock b/yarn.lock index fdf83db6c..15ba7ad63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -647,6 +647,18 @@ __metadata: languageName: node linkType: hard +"@helium/anchor-resolvers@npm:^0.6.42": + version: 0.6.42 + resolution: "@helium/anchor-resolvers@npm:0.6.42" + dependencies: + "@solana/spl-token": ^0.3.8 + "@solana/web3.js": ^1.78.4 + peerDependencies: + "@coral-xyz/anchor": ^0.28.0 + checksum: 25ceab8b1cb6a68fd95c5bf2d57f7a5faf5b473504d1e056588f0f6f8cf21401bb9edd84fb5df6d360af6198f1395d02f1a2e40b57f8da164677e8fb741d110a + languageName: node + linkType: hard + "@helium/circuit-breaker-sdk@^0.9.10, @helium/circuit-breaker-sdk@workspace:packages/circuit-breaker-sdk": version: 0.0.0-use.local resolution: "@helium/circuit-breaker-sdk@workspace:packages/circuit-breaker-sdk" @@ -663,6 +675,22 @@ __metadata: languageName: unknown linkType: soft +"@helium/conversion-escrow-sdk@workspace:packages/conversion-escrow-sdk": + version: 0.0.0-use.local + resolution: "@helium/conversion-escrow-sdk@workspace:packages/conversion-escrow-sdk" + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@helium/anchor-resolvers": ^0.6.42 + "@helium/idls": ^0.6.42 + bn.js: ^5.2.0 + bs58: ^4.0.1 + git-format-staged: ^2.1.3 + ts-loader: ^9.2.3 + ts-node: ^10.9.1 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + "@helium/crons@workspace:packages/crons": version: 0.0.0-use.local resolution: "@helium/crons@workspace:packages/crons" @@ -1106,6 +1134,19 @@ __metadata: languageName: node linkType: hard +"@helium/idls@npm:^0.6.42": + version: 0.6.42 + resolution: "@helium/idls@npm:0.6.42" + dependencies: + "@coral-xyz/anchor": ^0.28.0 + "@solana/web3.js": ^1.78.4 + bn.js: ^5.2.0 + borsh: ^0.7.0 + bs58: ^4.0.1 + checksum: 7285ccb1b171c2490f5d4071ff21d37c2ecccbd02d0499c007ee32b185c628b85c642cfcc3a020fe899434cbefcf45dbfacb69b9d6024c3be10576d43e9c2039 + languageName: node + linkType: hard + "@helium/lazy-distributor-sdk@^0.9.10, @helium/lazy-distributor-sdk@workspace:packages/lazy-distributor-sdk": version: 0.0.0-use.local resolution: "@helium/lazy-distributor-sdk@workspace:packages/lazy-distributor-sdk"