From 3a7f258111dd050577648352eb92f89abb2f0563 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 5 Nov 2024 14:41:55 -0700 Subject: [PATCH] almost ready for PR --- Cargo.lock | 176 +++++-- Cargo.toml | 1 + .../jito_tip_router/errors/jitoTipRouter.ts | 18 +- .../instructions/finalizeWeightTable.ts | 10 + .../instructions/updateWeightTable.ts | 17 +- clients/js/jito_tip_router/types/index.ts | 1 + .../js/jito_tip_router/types/jitoNumber.ts | 40 ++ .../js/jito_tip_router/types/weightEntry.ts | 16 +- .../src/generated/errors/jito_tip_router.rs | 12 + .../instructions/finalize_weight_table.rs | 40 ++ .../instructions/update_weight_table.rs | 50 +- .../src/generated/types/jito_number.rs | 13 + .../src/generated/types/mod.rs | 3 +- .../src/generated/types/weight_entry.rs | 4 +- core/Cargo.toml | 1 + core/src/depreciated_weight.rs | 474 ------------------ core/src/error.rs | 8 + core/src/instruction.rs | 5 +- core/src/jito_number.rs | 86 ++++ core/src/lib.rs | 1 + core/src/weight_table.rs | 96 +++- idl/jito_tip_router.json | 55 +- program/src/finalize_weight_table.rs | 7 +- program/src/lib.rs | 22 +- program/src/update_weight_table.rs | 18 +- 25 files changed, 532 insertions(+), 642 deletions(-) create mode 100644 clients/js/jito_tip_router/types/jitoNumber.ts create mode 100644 clients/rust/jito_tip_router/src/generated/types/jito_number.rs delete mode 100644 core/src/depreciated_weight.rs create mode 100644 core/src/jito_number.rs diff --git a/Cargo.lock b/Cargo.lock index b1ddcd1f..cf2f54e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,7 +250,7 @@ dependencies = [ "borsh 0.10.4", "bytemuck", "getrandom 0.2.15", - "solana-program", + "solana-program 1.18.26", "thiserror", ] @@ -1208,7 +1208,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279a4314e755fb311d9e2dd6503fdc023f9c833ddceb158565b95b9323f5fd10" dependencies = [ - "solana-program", + "solana-program 1.18.26", ] [[package]] @@ -2357,7 +2357,7 @@ dependencies = [ "borsh 0.10.4", "bytemuck", "jito-account-traits-derive", - "solana-program", + "solana-program 1.18.26", ] [[package]] @@ -2369,7 +2369,7 @@ dependencies = [ "bytemuck", "jito-bytemuck", "shank", - "solana-program", + "solana-program 1.18.26", "spl-associated-token-account", "spl-token", "spl-token-2022 3.0.4", @@ -2388,7 +2388,7 @@ dependencies = [ "num-traits", "serde", "serde_with 3.11.0", - "solana-program", + "solana-program 1.18.26", "solana-sdk", "thiserror", ] @@ -2404,7 +2404,7 @@ dependencies = [ "jito-jsm-core", "jito-restaking-sdk", "shank", - "solana-program", + "solana-program 1.18.26", "spl-associated-token-account", "spl-token", "thiserror", @@ -2424,7 +2424,7 @@ dependencies = [ "jito-restaking-sdk", "jito-vault-core", "shank", - "solana-program", + "solana-program 1.18.26", "solana-security-txt", "spl-associated-token-account", "spl-token", @@ -2439,7 +2439,7 @@ source = "git+https://github.com/jito-foundation/restaking.git#6dab154dbf8a60176 dependencies = [ "borsh 0.10.4", "shank", - "solana-program", + "solana-program 1.18.26", "thiserror", ] @@ -2462,7 +2462,7 @@ dependencies = [ "log", "solana-account-decoder", "solana-cli-config", - "solana-program", + "solana-program 1.18.26", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", @@ -2483,7 +2483,7 @@ dependencies = [ "num-traits", "serde", "serde_with 3.11.0", - "solana-program", + "solana-program 1.18.26", "solana-sdk", "thiserror", ] @@ -2502,8 +2502,9 @@ dependencies = [ "jito-vault-core", "jito-vault-sdk", "shank", - "solana-program", + "solana-program 1.18.26", "spl-associated-token-account", + "spl-math", "spl-token", "thiserror", ] @@ -2524,7 +2525,7 @@ dependencies = [ "jito-vault-sdk", "log", "shank", - "solana-program", + "solana-program 1.18.26", "solana-program-test", "solana-sdk", "solana-security-txt", @@ -2552,7 +2553,7 @@ dependencies = [ "jito-vault-core", "jito-vault-sdk", "shank", - "solana-program", + "solana-program 1.18.26", "solana-security-txt", "spl-associated-token-account", "spl-token", @@ -2584,7 +2585,7 @@ dependencies = [ "num-traits", "serde", "serde_with 3.11.0", - "solana-program", + "solana-program 1.18.26", "solana-sdk", "thiserror", ] @@ -2600,7 +2601,7 @@ dependencies = [ "jito-jsm-core", "jito-vault-sdk", "shank", - "solana-program", + "solana-program 1.18.26", "spl-associated-token-account", "spl-token", "spl-token-2022 3.0.4", @@ -2621,7 +2622,7 @@ dependencies = [ "jito-vault-core", "jito-vault-sdk", "shank", - "solana-program", + "solana-program 1.18.26", "solana-security-txt", "spl-associated-token-account", "spl-token", @@ -2636,7 +2637,7 @@ source = "git+https://github.com/jito-foundation/restaking.git#6dab154dbf8a60176 dependencies = [ "borsh 0.10.4", "shank", - "solana-program", + "solana-program 1.18.26", "spl-token", "thiserror", ] @@ -4440,7 +4441,7 @@ dependencies = [ "serde", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-program", + "solana-program 1.18.26", "solana-program-runtime", "solana-sdk", "thiserror", @@ -4455,7 +4456,7 @@ dependencies = [ "borsh 1.5.1", "futures", "solana-banks-interface", - "solana-program", + "solana-program 1.18.26", "solana-sdk", "tarpc", "thiserror", @@ -4858,13 +4859,59 @@ dependencies = [ "sha3 0.10.8", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-sdk-macro", + "solana-sdk-macro 1.18.26", "thiserror", "tiny-bip39", "wasm-bindgen", "zeroize", ] +[[package]] +name = "solana-program" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2625a23c3813b620141ee447819b08d1b9a5f1c69a309754834e3f35798a21fb" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.22.1", + "bincode", + "bitflags 2.6.0", + "blake3", + "borsh 0.10.4", + "borsh 1.5.1", + "bs58 0.5.1", + "bv", + "bytemuck", + "bytemuck_derive", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.15", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memoffset 0.9.1", + "num-bigint 0.4.6", + "num-derive 0.4.2", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-sdk-macro 2.0.14", + "thiserror", + "wasm-bindgen", +] + [[package]] name = "solana-program-runtime" version = "1.18.26" @@ -5190,8 +5237,8 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", - "solana-program", - "solana-sdk-macro", + "solana-program 1.18.26", + "solana-sdk-macro 1.18.26", "thiserror", "uriparse", "wasm-bindgen", @@ -5210,6 +5257,19 @@ dependencies = [ "syn 2.0.85", ] +[[package]] +name = "solana-sdk-macro" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93a5a1eabc890415d326707afe62cd7a2009236e8d899c1519566fc8f7e3977b" +dependencies = [ + "bs58 0.5.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.85", +] + [[package]] name = "solana-security-txt" version = "1.1.1" @@ -5424,7 +5484,7 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-metrics", - "solana-program", + "solana-program 1.18.26", "solana-program-runtime", "solana-sdk", "thiserror", @@ -5466,7 +5526,7 @@ dependencies = [ "serde", "serde_json", "sha3 0.9.1", - "solana-program", + "solana-program 1.18.26", "solana-sdk", "subtle", "thiserror", @@ -5524,7 +5584,7 @@ dependencies = [ "borsh 0.10.4", "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 1.18.26", "spl-token", "spl-token-2022 1.0.0", "thiserror", @@ -5537,7 +5597,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator-derive 0.1.2", ] @@ -5548,7 +5608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "210101376962bb22bb13be6daea34656ea1cbc248fce2164b146e39203b55e03" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator-derive 0.2.0", ] @@ -5600,13 +5660,27 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-math" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc5a6cc7a4f0cf7813ce44153bba73280909f697d7f6baf7b9f223a255e7887" +dependencies = [ + "borsh 1.5.1", + "num-derive 0.4.2", + "num-traits", + "solana-program 2.0.14", + "thiserror", + "uint", +] + [[package]] name = "spl-memo" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" dependencies = [ - "solana-program", + "solana-program 1.18.26", ] [[package]] @@ -5617,7 +5691,7 @@ checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" dependencies = [ "borsh 0.10.4", "bytemuck", - "solana-program", + "solana-program 1.18.26", "solana-zk-token-sdk", "spl-program-error 0.3.0", ] @@ -5630,7 +5704,7 @@ checksum = "c52d84c55efeef8edcc226743dc089d7e3888b8e3474569aa3eff152b37b9996" dependencies = [ "borsh 1.5.1", "bytemuck", - "solana-program", + "solana-program 1.18.26", "solana-zk-token-sdk", "spl-program-error 0.4.4", ] @@ -5643,7 +5717,7 @@ checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" dependencies = [ "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 1.18.26", "spl-program-error-derive 0.3.2", "thiserror", ] @@ -5656,7 +5730,7 @@ checksum = "e45a49acb925db68aa501b926096b2164adbdcade7a0c24152af9f0742d0a602" dependencies = [ "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 1.18.26", "spl-program-error-derive 0.4.1", "thiserror", ] @@ -5692,7 +5766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.1.0", "spl-pod 0.1.0", "spl-program-error 0.3.0", @@ -5706,7 +5780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fab8edfd37be5fa17c9e42c1bff86abbbaf0494b031b37957f2728ad2ff842ba" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.2.5", "spl-pod 0.2.5", "spl-program-error 0.4.4", @@ -5724,7 +5798,7 @@ dependencies = [ "num-derive 0.3.3", "num-traits", "num_enum 0.6.1", - "solana-program", + "solana-program 1.18.26", "thiserror", ] @@ -5739,7 +5813,7 @@ dependencies = [ "num-derive 0.4.2", "num-traits", "num_enum 0.7.3", - "solana-program", + "solana-program 1.18.26", "solana-security-txt", "solana-zk-token-sdk", "spl-memo", @@ -5763,7 +5837,7 @@ dependencies = [ "num-derive 0.4.2", "num-traits", "num_enum 0.7.3", - "solana-program", + "solana-program 1.18.26", "solana-security-txt", "solana-zk-token-sdk", "spl-memo", @@ -5783,7 +5857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.1.0", "spl-pod 0.1.0", "spl-program-error 0.3.0", @@ -5796,7 +5870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "014817d6324b1e20c4bbc883e8ee30a5faa13e59d91d1b2b95df98b920150c17" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.2.5", "spl-pod 0.2.5", "spl-program-error 0.4.4", @@ -5809,7 +5883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" dependencies = [ "borsh 0.10.4", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.1.0", "spl-pod 0.1.0", "spl-program-error 0.3.0", @@ -5823,7 +5897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3da00495b602ebcf5d8ba8b3ecff1ee454ce4c125c9077747be49c2d62335ba" dependencies = [ "borsh 1.5.1", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.2.5", "spl-pod 0.2.5", "spl-program-error 0.4.4", @@ -5838,7 +5912,7 @@ checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" dependencies = [ "arrayref", "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.1.0", "spl-pod 0.1.0", "spl-program-error 0.3.0", @@ -5854,7 +5928,7 @@ checksum = "a9b5c08a89838e5a2931f79b17f611857f281a14a2100968a3ccef352cb7414b" dependencies = [ "arrayref", "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.2.5", "spl-pod 0.2.5", "spl-program-error 0.4.4", @@ -5869,7 +5943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.1.0", "spl-pod 0.1.0", "spl-program-error 0.3.0", @@ -5882,7 +5956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c872f93d0600e743116501eba2d53460e73a12c9a496875a42a7d70e034fe06d" dependencies = [ "bytemuck", - "solana-program", + "solana-program 1.18.26", "spl-discriminator 0.2.5", "spl-pod 0.2.5", "spl-program-error 0.4.4", @@ -6495,6 +6569,18 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-bidi" version = "0.3.17" diff --git a/Cargo.toml b/Cargo.toml index 3fa60d62..6d71fef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ serde = { version = "^1.0", features = ["derive"] } serde_with = "3.9.0" shank = "0.4.2" shank_idl = "0.4.2" +spl-math = { version = "0.3.0", features = ["no-entrypoint"] } solana-account-decoder = "~1.18" solana-cli-config = "~1.18" solana-program = "~1.18" diff --git a/clients/js/jito_tip_router/errors/jitoTipRouter.ts b/clients/js/jito_tip_router/errors/jitoTipRouter.ts index 9fe38be9..6184f660 100644 --- a/clients/js/jito_tip_router/errors/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/errors/jitoTipRouter.ts @@ -22,28 +22,44 @@ export const JITO_TIP_ROUTER_ERROR__DENOMINATOR_IS_ZERO = 0x2100; // 8448 export const JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW = 0x2101; // 8449 /** ModuloOverflow: Modulo Overflow */ export const JITO_TIP_ROUTER_ERROR__MODULO_OVERFLOW = 0x2102; // 8450 +/** NewPreciseNumberError: New precise number error */ +export const JITO_TIP_ROUTER_ERROR__NEW_PRECISE_NUMBER_ERROR = 0x2103; // 8451 +/** CastToImpreciseNumberError: Cast to imprecise number error */ +export const JITO_TIP_ROUTER_ERROR__CAST_TO_IMPRECISE_NUMBER_ERROR = 0x2104; // 8452 /** IncorrectWeightTableAdmin: Incorrect weight table admin */ export const JITO_TIP_ROUTER_ERROR__INCORRECT_WEIGHT_TABLE_ADMIN = 0x2200; // 8704 /** CannotCreateFutureWeightTables: Cannnot create future weight tables */ export const JITO_TIP_ROUTER_ERROR__CANNOT_CREATE_FUTURE_WEIGHT_TABLES = 0x2201; // 8705 +/** WeightMintsDoNotMatchLength: Weight mints do not match - length */ +export const JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH = 0x2202; // 8706 +/** WeightMintsDoNotMatchMintHash: Weight mints do not match - mint hash */ +export const JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH = 0x2203; // 8707 export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW | typeof JITO_TIP_ROUTER_ERROR__CANNOT_CREATE_FUTURE_WEIGHT_TABLES + | typeof JITO_TIP_ROUTER_ERROR__CAST_TO_IMPRECISE_NUMBER_ERROR | typeof JITO_TIP_ROUTER_ERROR__DENOMINATOR_IS_ZERO | typeof JITO_TIP_ROUTER_ERROR__INCORRECT_WEIGHT_TABLE_ADMIN | typeof JITO_TIP_ROUTER_ERROR__MODULO_OVERFLOW - | typeof JITO_TIP_ROUTER_ERROR__NO_MORE_TABLE_SLOTS; + | typeof JITO_TIP_ROUTER_ERROR__NEW_PRECISE_NUMBER_ERROR + | typeof JITO_TIP_ROUTER_ERROR__NO_MORE_TABLE_SLOTS + | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH + | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH; let jitoTipRouterErrorMessages: Record | undefined; if (process.env.NODE_ENV !== 'production') { jitoTipRouterErrorMessages = { [JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW]: `Overflow`, [JITO_TIP_ROUTER_ERROR__CANNOT_CREATE_FUTURE_WEIGHT_TABLES]: `Cannnot create future weight tables`, + [JITO_TIP_ROUTER_ERROR__CAST_TO_IMPRECISE_NUMBER_ERROR]: `Cast to imprecise number error`, [JITO_TIP_ROUTER_ERROR__DENOMINATOR_IS_ZERO]: `Zero in the denominator`, [JITO_TIP_ROUTER_ERROR__INCORRECT_WEIGHT_TABLE_ADMIN]: `Incorrect weight table admin`, [JITO_TIP_ROUTER_ERROR__MODULO_OVERFLOW]: `Modulo Overflow`, + [JITO_TIP_ROUTER_ERROR__NEW_PRECISE_NUMBER_ERROR]: `New precise number error`, [JITO_TIP_ROUTER_ERROR__NO_MORE_TABLE_SLOTS]: `No more table slots available`, + [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH]: `Weight mints do not match - length`, + [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH]: `Weight mints do not match - mint hash`, }; } diff --git a/clients/js/jito_tip_router/instructions/finalizeWeightTable.ts b/clients/js/jito_tip_router/instructions/finalizeWeightTable.ts index f492b8a7..ff56556f 100644 --- a/clients/js/jito_tip_router/instructions/finalizeWeightTable.ts +++ b/clients/js/jito_tip_router/instructions/finalizeWeightTable.ts @@ -67,10 +67,14 @@ export type FinalizeWeightTableInstruction< export type FinalizeWeightTableInstructionData = { discriminator: number; ncnEpoch: bigint; + mintHash: bigint; + mintCount: number; }; export type FinalizeWeightTableInstructionDataArgs = { ncnEpoch: number | bigint; + mintHash: number | bigint; + mintCount: number; }; export function getFinalizeWeightTableInstructionDataEncoder(): Encoder { @@ -78,6 +82,8 @@ export function getFinalizeWeightTableInstructionDataEncoder(): Encoder ({ ...value, @@ -90,6 +96,8 @@ export function getFinalizeWeightTableInstructionDataDecoder(): Decoder; restakingProgramId: Address; ncnEpoch: FinalizeWeightTableInstructionDataArgs['ncnEpoch']; + mintHash: FinalizeWeightTableInstructionDataArgs['mintHash']; + mintCount: FinalizeWeightTableInstructionDataArgs['mintCount']; }; export function getFinalizeWeightTableInstruction< diff --git a/clients/js/jito_tip_router/instructions/updateWeightTable.ts b/clients/js/jito_tip_router/instructions/updateWeightTable.ts index 91577086..0fd6673d 100644 --- a/clients/js/jito_tip_router/instructions/updateWeightTable.ts +++ b/clients/js/jito_tip_router/instructions/updateWeightTable.ts @@ -10,6 +10,8 @@ import { combineCodec, getStructDecoder, getStructEncoder, + getU128Decoder, + getU128Encoder, getU64Decoder, getU64Encoder, getU8Decoder, @@ -67,14 +69,12 @@ export type UpdateWeightTableInstruction< export type UpdateWeightTableInstructionData = { discriminator: number; ncnEpoch: bigint; - weightNumerator: bigint; - weightDenominator: bigint; + weight: bigint; }; export type UpdateWeightTableInstructionDataArgs = { ncnEpoch: number | bigint; - weightNumerator: number | bigint; - weightDenominator: number | bigint; + weight: number | bigint; }; export function getUpdateWeightTableInstructionDataEncoder(): Encoder { @@ -82,8 +82,7 @@ export function getUpdateWeightTableInstructionDataEncoder(): Encoder ({ ...value, discriminator: UPDATE_WEIGHT_TABLE_DISCRIMINATOR }) ); @@ -93,8 +92,7 @@ export function getUpdateWeightTableInstructionDataDecoder(): Decoder; restakingProgramId: Address; ncnEpoch: UpdateWeightTableInstructionDataArgs['ncnEpoch']; - weightNumerator: UpdateWeightTableInstructionDataArgs['weightNumerator']; - weightDenominator: UpdateWeightTableInstructionDataArgs['weightDenominator']; + weight: UpdateWeightTableInstructionDataArgs['weight']; }; export function getUpdateWeightTableInstruction< diff --git a/clients/js/jito_tip_router/types/index.ts b/clients/js/jito_tip_router/types/index.ts index 5597466b..0c7494d1 100644 --- a/clients/js/jito_tip_router/types/index.ts +++ b/clients/js/jito_tip_router/types/index.ts @@ -6,4 +6,5 @@ * @see https://github.com/kinobi-so/kinobi */ +export * from './jitoNumber'; export * from './weightEntry'; diff --git a/clients/js/jito_tip_router/types/jitoNumber.ts b/clients/js/jito_tip_router/types/jitoNumber.ts new file mode 100644 index 00000000..53470322 --- /dev/null +++ b/clients/js/jito_tip_router/types/jitoNumber.ts @@ -0,0 +1,40 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + getArrayDecoder, + getArrayEncoder, + getStructDecoder, + getStructEncoder, + getU8Decoder, + getU8Encoder, + type Codec, + type Decoder, + type Encoder, +} from '@solana/web3.js'; + +export type JitoNumber = { value: Array }; + +export type JitoNumberArgs = JitoNumber; + +export function getJitoNumberEncoder(): Encoder { + return getStructEncoder([ + ['value', getArrayEncoder(getU8Encoder(), { size: 16 })], + ]); +} + +export function getJitoNumberDecoder(): Decoder { + return getStructDecoder([ + ['value', getArrayDecoder(getU8Decoder(), { size: 16 })], + ]); +} + +export function getJitoNumberCodec(): Codec { + return combineCodec(getJitoNumberEncoder(), getJitoNumberDecoder()); +} diff --git a/clients/js/jito_tip_router/types/weightEntry.ts b/clients/js/jito_tip_router/types/weightEntry.ts index 745e0002..bf66fd31 100644 --- a/clients/js/jito_tip_router/types/weightEntry.ts +++ b/clients/js/jito_tip_router/types/weightEntry.ts @@ -12,29 +12,33 @@ import { getAddressEncoder, getStructDecoder, getStructEncoder, - getU64Decoder, - getU64Encoder, type Address, type Codec, type Decoder, type Encoder, } from '@solana/web3.js'; +import { + getJitoNumberDecoder, + getJitoNumberEncoder, + type JitoNumber, + type JitoNumberArgs, +} from '.'; -export type WeightEntry = { mint: Address; weight: bigint }; +export type WeightEntry = { mint: Address; weight: JitoNumber }; -export type WeightEntryArgs = { mint: Address; weight: number | bigint }; +export type WeightEntryArgs = { mint: Address; weight: JitoNumberArgs }; export function getWeightEntryEncoder(): Encoder { return getStructEncoder([ ['mint', getAddressEncoder()], - ['weight', getU64Encoder()], + ['weight', getJitoNumberEncoder()], ]); } export function getWeightEntryDecoder(): Decoder { return getStructDecoder([ ['mint', getAddressDecoder()], - ['weight', getU64Decoder()], + ['weight', getJitoNumberDecoder()], ]); } diff --git a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs index 99bb8322..9191ec4b 100644 --- a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs +++ b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs @@ -21,12 +21,24 @@ pub enum JitoTipRouterError { /// 8450 - Modulo Overflow #[error("Modulo Overflow")] ModuloOverflow = 0x2102, + /// 8451 - New precise number error + #[error("New precise number error")] + NewPreciseNumberError = 0x2103, + /// 8452 - Cast to imprecise number error + #[error("Cast to imprecise number error")] + CastToImpreciseNumberError = 0x2104, /// 8704 - Incorrect weight table admin #[error("Incorrect weight table admin")] IncorrectWeightTableAdmin = 0x2200, /// 8705 - Cannnot create future weight tables #[error("Cannnot create future weight tables")] CannotCreateFutureWeightTables = 0x2201, + /// 8706 - Weight mints do not match - length + #[error("Weight mints do not match - length")] + WeightMintsDoNotMatchLength = 0x2202, + /// 8707 - Weight mints do not match - mint hash + #[error("Weight mints do not match - mint hash")] + WeightMintsDoNotMatchMintHash = 0x2203, } impl solana_program::program_error::PrintProgramError for JitoTipRouterError { diff --git a/clients/rust/jito_tip_router/src/generated/instructions/finalize_weight_table.rs b/clients/rust/jito_tip_router/src/generated/instructions/finalize_weight_table.rs index ab492289..f811789d 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/finalize_weight_table.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/finalize_weight_table.rs @@ -82,6 +82,8 @@ impl Default for FinalizeWeightTableInstructionData { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FinalizeWeightTableInstructionArgs { pub ncn_epoch: u64, + pub mint_hash: u64, + pub mint_count: u8, } /// Instruction builder for `FinalizeWeightTable`. @@ -99,6 +101,8 @@ pub struct FinalizeWeightTableBuilder { weight_table_admin: Option, restaking_program_id: Option, ncn_epoch: Option, + mint_hash: Option, + mint_count: Option, __remaining_accounts: Vec, } @@ -137,6 +141,16 @@ impl FinalizeWeightTableBuilder { self.ncn_epoch = Some(ncn_epoch); self } + #[inline(always)] + pub fn mint_hash(&mut self, mint_hash: u64) -> &mut Self { + self.mint_hash = Some(mint_hash); + self + } + #[inline(always)] + pub fn mint_count(&mut self, mint_count: u8) -> &mut Self { + self.mint_count = Some(mint_count); + self + } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -169,6 +183,8 @@ impl FinalizeWeightTableBuilder { }; let args = FinalizeWeightTableInstructionArgs { ncn_epoch: self.ncn_epoch.clone().expect("ncn_epoch is not set"), + mint_hash: self.mint_hash.clone().expect("mint_hash is not set"), + mint_count: self.mint_count.clone().expect("mint_count is not set"), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -325,6 +341,8 @@ impl<'a, 'b> FinalizeWeightTableCpiBuilder<'a, 'b> { weight_table_admin: None, restaking_program_id: None, ncn_epoch: None, + mint_hash: None, + mint_count: None, __remaining_accounts: Vec::new(), }); Self { instruction } @@ -363,6 +381,16 @@ impl<'a, 'b> FinalizeWeightTableCpiBuilder<'a, 'b> { self.instruction.ncn_epoch = Some(ncn_epoch); self } + #[inline(always)] + pub fn mint_hash(&mut self, mint_hash: u64) -> &mut Self { + self.instruction.mint_hash = Some(mint_hash); + self + } + #[inline(always)] + pub fn mint_count(&mut self, mint_count: u8) -> &mut Self { + self.instruction.mint_count = Some(mint_count); + self + } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -410,6 +438,16 @@ impl<'a, 'b> FinalizeWeightTableCpiBuilder<'a, 'b> { .ncn_epoch .clone() .expect("ncn_epoch is not set"), + mint_hash: self + .instruction + .mint_hash + .clone() + .expect("mint_hash is not set"), + mint_count: self + .instruction + .mint_count + .clone() + .expect("mint_count is not set"), }; let instruction = FinalizeWeightTableCpi { __program: self.instruction.__program, @@ -447,6 +485,8 @@ struct FinalizeWeightTableCpiBuilderInstruction<'a, 'b> { weight_table_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn_epoch: Option, + mint_hash: Option, + mint_count: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<( &'b solana_program::account_info::AccountInfo<'a>, diff --git a/clients/rust/jito_tip_router/src/generated/instructions/update_weight_table.rs b/clients/rust/jito_tip_router/src/generated/instructions/update_weight_table.rs index 224b8aed..d2aa8173 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/update_weight_table.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/update_weight_table.rs @@ -82,8 +82,7 @@ impl Default for UpdateWeightTableInstructionData { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct UpdateWeightTableInstructionArgs { pub ncn_epoch: u64, - pub weight_numerator: u64, - pub weight_denominator: u64, + pub weight: u128, } /// Instruction builder for `UpdateWeightTable`. @@ -101,8 +100,7 @@ pub struct UpdateWeightTableBuilder { weight_table_admin: Option, restaking_program_id: Option, ncn_epoch: Option, - weight_numerator: Option, - weight_denominator: Option, + weight: Option, __remaining_accounts: Vec, } @@ -142,13 +140,8 @@ impl UpdateWeightTableBuilder { self } #[inline(always)] - pub fn weight_numerator(&mut self, weight_numerator: u64) -> &mut Self { - self.weight_numerator = Some(weight_numerator); - self - } - #[inline(always)] - pub fn weight_denominator(&mut self, weight_denominator: u64) -> &mut Self { - self.weight_denominator = Some(weight_denominator); + pub fn weight(&mut self, weight: u128) -> &mut Self { + self.weight = Some(weight); self } /// Add an additional account to the instruction. @@ -183,14 +176,7 @@ impl UpdateWeightTableBuilder { }; let args = UpdateWeightTableInstructionArgs { ncn_epoch: self.ncn_epoch.clone().expect("ncn_epoch is not set"), - weight_numerator: self - .weight_numerator - .clone() - .expect("weight_numerator is not set"), - weight_denominator: self - .weight_denominator - .clone() - .expect("weight_denominator is not set"), + weight: self.weight.clone().expect("weight is not set"), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -347,8 +333,7 @@ impl<'a, 'b> UpdateWeightTableCpiBuilder<'a, 'b> { weight_table_admin: None, restaking_program_id: None, ncn_epoch: None, - weight_numerator: None, - weight_denominator: None, + weight: None, __remaining_accounts: Vec::new(), }); Self { instruction } @@ -388,13 +373,8 @@ impl<'a, 'b> UpdateWeightTableCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn weight_numerator(&mut self, weight_numerator: u64) -> &mut Self { - self.instruction.weight_numerator = Some(weight_numerator); - self - } - #[inline(always)] - pub fn weight_denominator(&mut self, weight_denominator: u64) -> &mut Self { - self.instruction.weight_denominator = Some(weight_denominator); + pub fn weight(&mut self, weight: u128) -> &mut Self { + self.instruction.weight = Some(weight); self } /// Add an additional account to the instruction. @@ -444,16 +424,7 @@ impl<'a, 'b> UpdateWeightTableCpiBuilder<'a, 'b> { .ncn_epoch .clone() .expect("ncn_epoch is not set"), - weight_numerator: self - .instruction - .weight_numerator - .clone() - .expect("weight_numerator is not set"), - weight_denominator: self - .instruction - .weight_denominator - .clone() - .expect("weight_denominator is not set"), + weight: self.instruction.weight.clone().expect("weight is not set"), }; let instruction = UpdateWeightTableCpi { __program: self.instruction.__program, @@ -491,8 +462,7 @@ struct UpdateWeightTableCpiBuilderInstruction<'a, 'b> { weight_table_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn_epoch: Option, - weight_numerator: Option, - weight_denominator: Option, + weight: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<( &'b solana_program::account_info::AccountInfo<'a>, diff --git a/clients/rust/jito_tip_router/src/generated/types/jito_number.rs b/clients/rust/jito_tip_router/src/generated/types/jito_number.rs new file mode 100644 index 00000000..76e377d7 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/types/jito_number.rs @@ -0,0 +1,13 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct JitoNumber { + pub value: [u8; 16], +} diff --git a/clients/rust/jito_tip_router/src/generated/types/mod.rs b/clients/rust/jito_tip_router/src/generated/types/mod.rs index f552bf2d..be8e546f 100644 --- a/clients/rust/jito_tip_router/src/generated/types/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/types/mod.rs @@ -4,6 +4,7 @@ //! //! +pub(crate) mod r#jito_number; pub(crate) mod r#weight_entry; -pub use self::r#weight_entry::*; +pub use self::{r#jito_number::*, r#weight_entry::*}; diff --git a/clients/rust/jito_tip_router/src/generated/types/weight_entry.rs b/clients/rust/jito_tip_router/src/generated/types/weight_entry.rs index 11a9d118..67e77cff 100644 --- a/clients/rust/jito_tip_router/src/generated/types/weight_entry.rs +++ b/clients/rust/jito_tip_router/src/generated/types/weight_entry.rs @@ -7,6 +7,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::pubkey::Pubkey; +use crate::generated::types::JitoNumber; + #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct WeightEntry { @@ -15,5 +17,5 @@ pub struct WeightEntry { serde(with = "serde_with::As::") )] pub mint: Pubkey, - pub weight: u64, + pub weight: JitoNumber, } diff --git a/core/Cargo.toml b/core/Cargo.toml index fabfd39c..1aa25c24 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -21,6 +21,7 @@ jito-vault-sdk = { workspace = true } shank = { workspace = true } solana-program = { workspace = true } spl-associated-token-account = { workspace = true } +spl-math = { workspace = true } spl-token = { workspace = true } thiserror = { workspace = true } diff --git a/core/src/depreciated_weight.rs b/core/src/depreciated_weight.rs deleted file mode 100644 index 224069d7..00000000 --- a/core/src/depreciated_weight.rs +++ /dev/null @@ -1,474 +0,0 @@ -use std::u64; - -use bytemuck::{Pod, Zeroable}; -use jito_bytemuck::types::PodU64; -use shank::ShankType; - -use crate::error::WeightTableError; - -#[derive(Debug, Clone, PartialEq, Eq, Copy, Zeroable, ShankType, Pod)] -#[repr(C)] -pub struct Weight { - numerator: PodU64, - denominator: PodU64, -} - -impl Weight { - pub fn numerator(&self) -> u64 { - self.numerator.into() - } - - pub fn denominator(&self) -> u64 { - self.denominator.into() - } - - pub fn new(numerator: u64, denominator: u64) -> Result { - if denominator == 0 { - return Err(WeightTableError::DenominatorIsZero); - } - - Ok(Self { - numerator: PodU64::from(numerator), - denominator: PodU64::from(denominator), - }) - } - - fn is_zero(&self) -> bool { - self.numerator() == 0 - } - - fn greatest_common_denominator(&self) -> Result { - let mut n: u64 = self.numerator(); - let mut d: u64 = self.denominator(); - - if d == 0 { - return Err(WeightTableError::DenominatorIsZero); - } - - if n == 0 { - return Ok(1); - } - - while d != 0 { - if d < n { - std::mem::swap(&mut d, &mut n); - } - d %= n; - } - - Ok(n) - } - - fn simplify(&self) -> Result { - let gcd_value = self.greatest_common_denominator()?; - - if gcd_value == 1 { - return Ok(*self); - } - - Ok(Self { - numerator: PodU64::from(self.numerator() / gcd_value), - denominator: PodU64::from(self.denominator() / gcd_value), - }) - } - - fn compare_weights(&self, other: &Self, compare: F) -> bool - where - F: Fn(u64, u64) -> bool, - { - let a = self.numerator(); - let b = self.denominator(); - let c = other.numerator(); - let d = other.denominator(); - - a.checked_mul(d) - .and_then(|ad| b.checked_mul(c).map(|bc| compare(ad, bc))) - .unwrap_or(false) - } - - pub fn gte(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad >= bc) - } - - pub fn gt(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad > bc) - } - - pub fn lt(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad < bc) - } - - pub fn lte(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad <= bc) - } - - pub fn eq(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad == bc) - } - - pub fn neq(&self, other: &Self) -> bool { - self.compare_weights(other, |ad, bc| ad != bc) - } - - pub fn checked_add(&self, other: &Self) -> Result { - let a = self.numerator(); - let b = self.denominator(); - let c = other.numerator(); - let d = other.denominator(); - - // Calculate ad and bc - let ad = a - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - let bc = b - .checked_mul(c) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate numerator (ad + bc) - let numerator = ad - .checked_add(bc) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate denominator (bd) - let denominator = b - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - let weight = Self { - numerator: PodU64::from(numerator), - denominator: PodU64::from(denominator), - }; - - weight.simplify() - } - - pub fn checked_sub(&self, other: &Self) -> Result { - let a = self.numerator(); - let b = self.denominator(); - let c = other.numerator(); - let d = other.denominator(); - - // Calculate ad and bc - let ad = a - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - let bc = b - .checked_mul(c) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate numerator (ad - bc) - let numerator = ad - .checked_sub(bc) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate denominator (bd) - let denominator = b - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Check if the result is zero - if numerator == 0 { - return Ok(Self::default()); - } - - let weight = Self { - numerator: PodU64::from(numerator), - denominator: PodU64::from(denominator), - }; - - weight.simplify() - } - - pub fn checked_mul(&self, other: &Self) -> Result { - let a = self.numerator(); - let b = self.denominator(); - let c = other.numerator(); - let d = other.denominator(); - - // Calculate numerator (ac) - let numerator = a - .checked_mul(c) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate denominator (bd) - let denominator = b - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - if denominator == 0 { - return Err(WeightTableError::DenominatorIsZero); - } - - let weight = Self { - numerator: PodU64::from(numerator), - denominator: PodU64::from(denominator), - }; - - weight.simplify() - } - - pub fn checked_div(&self, other: &Self) -> Result { - if other.is_zero() { - return Err(WeightTableError::DenominatorIsZero); - } - - let a = self.numerator(); - let b = self.denominator(); - let c = other.numerator(); - let d = other.denominator(); - - // Division by a/b / c/d is equivalent to multiplication by a/b * d/c - // So we multiply by the reciprocal - - // Calculate numerator (ad) - let numerator = a - .checked_mul(d) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - // Calculate denominator (bc) - let denominator = b - .checked_mul(c) - .ok_or(WeightTableError::ArithmeticOverflow)?; - - if denominator == 0 { - return Err(WeightTableError::DenominatorIsZero); - } - - let weight = Self { - numerator: PodU64::from(numerator), - denominator: PodU64::from(denominator), - }; - - weight.simplify() - } -} - -impl Default for Weight { - fn default() -> Self { - Self { - numerator: PodU64::from(0), - denominator: PodU64::from(1), - } - } -} - -impl From for Weight { - fn from(weight: u64) -> Self { - Self { - numerator: PodU64::from(weight), - denominator: PodU64::from(1), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_new() { - assert!(Weight::new(1, 2).is_ok()); - assert!(matches!( - Weight::new(1, 0), - Err(WeightTableError::DenominatorIsZero) - )); - } - - #[test] - fn test_is_zero() { - assert!(Weight::new(0, 1).unwrap().is_zero()); - assert!(!Weight::new(1, 2).unwrap().is_zero()); - } - - #[test] - fn test_gcd() { - assert_eq!( - Weight::new(6, 8) - .unwrap() - .greatest_common_denominator() - .unwrap(), - 2 - ); - assert_eq!( - Weight::new(17, 23) - .unwrap() - .greatest_common_denominator() - .unwrap(), - 1 - ); - - let bad_weight = Weight::new(1, 0).unwrap_err(); - assert!(matches!(bad_weight, WeightTableError::DenominatorIsZero)); - } - - #[test] - fn test_simplify() { - let w1 = Weight::new(6, 8).unwrap().simplify().unwrap(); - assert_eq!(w1.numerator(), 3); - assert_eq!(w1.denominator(), 4); - - let w2 = Weight::new(17, 23).unwrap().simplify().unwrap(); - assert_eq!(w2.numerator(), 17); - assert_eq!(w2.denominator(), 23); - } - - #[test] - fn test_comparisons() { - let w1 = Weight::new(1, 2).unwrap(); - let w2 = Weight::new(3, 4).unwrap(); - let w3 = Weight::new(1, 2).unwrap(); - - assert!(w1.lt(&w2)); - assert!(w1.lte(&w2)); - assert!(w2.gt(&w1)); - assert!(w2.gte(&w1)); - assert!(w1.eq(&w3)); - assert!(w1.neq(&w2)); - } - - #[test] - fn test_checked_add() { - let w1 = Weight::new(1, 2).unwrap(); - let w2 = Weight::new(1, 4).unwrap(); - let result = w1.checked_add(&w2).unwrap(); - assert_eq!(result.numerator(), 3); - assert_eq!(result.denominator(), 4); - - // Test overflow - let w_max = Weight::new(u64::MAX, 1).unwrap(); - assert!(matches!( - w_max.checked_add(&w1), - Err(WeightTableError::ArithmeticOverflow) - )); - } - - #[test] - fn test_checked_sub() { - let w1 = Weight::new(3, 4).unwrap(); - let w2 = Weight::new(1, 4).unwrap(); - let result = w1.checked_sub(&w2).unwrap(); - assert_eq!(result.numerator(), 1); - assert_eq!(result.denominator(), 2); - - // Test underflow - let w_min = Weight::new(0, 1).unwrap(); - assert!(matches!( - w_min.checked_sub(&w1), - Err(WeightTableError::ArithmeticOverflow) - )); - } - - #[test] - fn test_checked_mul() { - let w1 = Weight::new(2, 3).unwrap(); - let w2 = Weight::new(3, 4).unwrap(); - let result = w1.checked_mul(&w2).unwrap(); - assert_eq!(result.numerator(), 1); - assert_eq!(result.denominator(), 2); - - // Test overflow - let w_max = Weight::new(u64::MAX, 1).unwrap(); - assert!(matches!( - w_max.checked_mul(&w1), - Err(WeightTableError::ArithmeticOverflow) - )); - } - - #[test] - fn test_checked_div() { - let w1 = Weight::new(2, 3).unwrap(); - let w2 = Weight::new(3, 4).unwrap(); - let result = w1.checked_div(&w2).unwrap(); - assert_eq!(result.numerator(), 8); - assert_eq!(result.denominator(), 9); - - // Test division by zero - let w_zero = Weight::new(0, 1).unwrap(); - assert!(matches!( - w1.checked_div(&w_zero), - Err(WeightTableError::DenominatorIsZero) - )); - - // Test overflow - let w_max = Weight::new(u64::MAX, 1).unwrap(); - let w_min = Weight::new(1, u64::MAX).unwrap(); - assert!(matches!( - w_max.checked_div(&w_min), - Err(WeightTableError::ArithmeticOverflow) - )); - } - - #[test] - fn test_largest_and_smallest_comparison() { - let largest = Weight::new(u64::MAX, 1).unwrap(); - let smallest = Weight::new(1, u64::MAX).unwrap(); - - // Due to overflow protection, these comparisons will return false - assert!(!largest.gt(&smallest)); - assert!(!smallest.lt(&largest)); - assert!(!largest.eq(&smallest)); - } - - #[test] - fn test_large_number_comparison() { - let large1 = Weight::new(u64::MAX / 2, 1).unwrap(); - let large2 = Weight::new(u64::MAX / 2 + 1, 1).unwrap(); - - assert!(large2.gt(&large1)); - assert!(large1.lt(&large2)); - assert!(!large1.eq(&large2)); - } - - #[test] - fn test_small_number_comparison() { - let small1 = Weight::new(1, u64::MAX).unwrap(); - let small2 = Weight::new(2, u64::MAX).unwrap(); - - // Due to precision limitations, these might not compare as expected - assert!(!small2.gt(&small1)); - assert!(!small1.lt(&small2)); - assert!(!small1.eq(&small2)); - } - - #[test] - fn test_precision_limit() { - let w1 = Weight::new(u64::MAX / 2, u64::MAX / 2).unwrap(); - let w2 = Weight::new(u64::MAX / 2 + 1, u64::MAX / 2).unwrap(); - - // Due to overflow protection, these comparisons will return false - assert!(!w2.gt(&w1)); - assert!(!w1.lt(&w2)); - assert!(!w1.eq(&w2)); - } - - #[test] - fn test_overflow_handling() { - let w1 = Weight::new(u64::MAX, 2).unwrap(); - let w2 = Weight::new(u64::MAX - 1, 2).unwrap(); - - // This comparison should return false due to overflow protection - assert!(!w1.gt(&w2)); - assert!(!w1.lt(&w2)); - assert!(!w1.eq(&w2)); - } - - #[test] - fn test_equality_of_simplified_weights() { - let w1 = Weight::new(2, 4).unwrap(); - let w2 = Weight::new(1, 2).unwrap(); - - assert!(w1.eq(&w2)); - assert!(!w1.gt(&w2)); - assert!(!w1.lt(&w2)); - } - - #[test] - fn test_comparison_with_zero() { - let zero = Weight::new(0, 1).unwrap(); - let smallest_positive = Weight::new(1, u64::MAX).unwrap(); - - assert!(smallest_positive.gt(&zero)); - assert!(zero.lt(&smallest_positive)); - assert!(!zero.eq(&smallest_positive)); - } -} diff --git a/core/src/error.rs b/core/src/error.rs index 1e359391..128fac86 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -11,11 +11,19 @@ pub enum TipRouterError { ArithmeticOverflow = 0x2101, #[error("Modulo Overflow")] ModuloOverflow = 0x2102, + #[error("New precise number error")] + NewPreciseNumberError = 0x2103, + #[error("Cast to imprecise number error")] + CastToImpreciseNumberError = 0x2104, #[error("Incorrect weight table admin")] IncorrectWeightTableAdmin = 0x2200, #[error("Cannnot create future weight tables")] CannotCreateFutureWeightTables = 0x2201, + #[error("Weight mints do not match - length")] + WeightMintsDoNotMatchLength = 0x2202, + #[error("Weight mints do not match - mint hash")] + WeightMintsDoNotMatchMintHash = 0x2203, } impl DecodeError for TipRouterError { diff --git a/core/src/instruction.rs b/core/src/instruction.rs index 4280e994..8f5bf065 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -23,8 +23,7 @@ pub enum WeightTableInstruction { #[account(3, name = "restaking_program_id")] UpdateWeightTable{ ncn_epoch: u64, - weight_numerator: u64, - weight_denominator: u64, + weight: u128, }, #[account(0, name = "ncn")] @@ -33,6 +32,8 @@ pub enum WeightTableInstruction { #[account(3, name = "restaking_program_id")] FinalizeWeightTable{ ncn_epoch: u64, + mint_hash: u64, + mint_count: u8, }, } diff --git a/core/src/jito_number.rs b/core/src/jito_number.rs new file mode 100644 index 00000000..47c53aa6 --- /dev/null +++ b/core/src/jito_number.rs @@ -0,0 +1,86 @@ +use bytemuck::{Pod, Zeroable}; +use shank::ShankType; +use spl_math::precise_number::PreciseNumber; + +use crate::error::TipRouterError; + +// Weights are stored as the number of tokens +#[derive(Default, Debug, Clone, Copy, Zeroable, ShankType, Pod)] +#[repr(C)] +pub struct JitoNumber { + value: [u8; 16], // 128 +} + +impl JitoNumber { + pub const PRECISION_FACTOR: u128 = 1_000_000_000; + + const fn _from_u128(value: u128) -> Self { + let value = value.to_le_bytes(); + Self { value } + } + + const fn _to_u128(&self) -> u128 { + u128::from_le_bytes(self.value) + } + + fn _to_precise_number(&self) -> Result { + PreciseNumber::new(self._to_u128()).ok_or(TipRouterError::NewPreciseNumberError) + } + + fn _from_precise_number(precise_number: PreciseNumber) -> Result { + let value = precise_number + .to_imprecise() + .ok_or(TipRouterError::CastToImpreciseNumberError)?; + + Ok(Self::_from_u128(value)) + } + + fn from_token_supply(token_supply: u64) -> Result { + let value = (token_supply as u128) + .checked_mul(Self::PRECISION_FACTOR) + .ok_or(TipRouterError::ArithmeticOverflow)?; + + Ok(Self::_from_u128(value)) + } + + fn to_token_supply(self) -> Result { + let value = self._to_u128(); + let token_supply = value + .checked_div(Self::PRECISION_FACTOR) + .ok_or(TipRouterError::ArithmeticOverflow)?; + + token_supply + .try_into() + .map_err(|_| TipRouterError::ArithmeticOverflow) + } + + pub fn token_supply_to_precise_number( + token_supply: u64, + ) -> Result { + let value = Self::from_token_supply(token_supply)?; + value._to_precise_number() + } + + pub fn precise_number_to_token_supply( + precise_number: PreciseNumber, + ) -> Result { + let value = Self::_from_precise_number(precise_number)?; + value.to_token_supply() + } + + pub const fn from_weight(weight: u128) -> Self { + Self::_from_u128(weight) + } + + pub const fn to_weight(&self) -> u128 { + self._to_u128() + } + + pub fn weight_to_precise_number(&self) -> Result { + self._to_precise_number() + } + + pub fn precise_number_to_weight(precise_number: PreciseNumber) -> Result { + Self::_from_precise_number(precise_number) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index a5682335..2f29758a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -2,4 +2,5 @@ pub mod discriminators; pub mod error; pub mod instruction; // pub mod depreciated_weight; +pub mod jito_number; pub mod weight_table; diff --git a/core/src/weight_table.rs b/core/src/weight_table.rs index 61bd2ac7..99130ba1 100644 --- a/core/src/weight_table.rs +++ b/core/src/weight_table.rs @@ -3,7 +3,7 @@ use jito_bytemuck::{types::PodU64, AccountDeserialize, Discriminator}; use shank::{ShankAccount, ShankType}; use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; -use crate::{discriminators::Discriminators, error::TipRouterError}; +use crate::{discriminators::Discriminators, error::TipRouterError, jito_number::JitoNumber}; // PDA'd ["WEIGHT_TABLE", NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] @@ -11,10 +11,10 @@ use crate::{discriminators::Discriminators, error::TipRouterError}; pub struct WeightTable { /// The NCN on-chain program is the signer to create and update this account, /// this pushes the responsibility of managing the account to the NCN program. - pub ncn: Pubkey, + ncn: Pubkey, /// The NCN epoch for which the weight table is valid - pub ncn_epoch: PodU64, + ncn_epoch: PodU64, /// Slot weight table was created slot_created: PodU64, @@ -23,13 +23,13 @@ pub struct WeightTable { slot_finalized: PodU64, /// Bump seed for the PDA - pub bump: u8, + bump: u8, /// Reserved space reserved: [u8; 128], /// The weight table - pub table: [WeightEntry; 32], + table: [WeightEntry; 32], } impl Discriminator for WeightTable { @@ -75,35 +75,79 @@ impl WeightTable { (pda, bump, seeds) } + pub fn get_mints(&self) -> Vec { + self.table + .iter() + .filter(|entry| !entry.is_empty()) + .map(|entry| entry.mint) + .collect() + } + + pub fn get_mint_hash(mints: Vec) -> u64 { + let mut hash = 0; + + // Makes sure the hash is the same regardless of the order of the mints + let mut sorted_mints = mints; + sorted_mints.sort(); + + for mint in sorted_mints { + let bytes = mint.to_bytes(); + let u64_slice = u64::from_le_bytes(bytes[0..8].try_into().unwrap()); + + hash ^= u64_slice; + } + + hash + } + + pub fn check_mints_okay(&self, mint_hash: u64, mint_count: u8) -> Result<(), TipRouterError> { + if mint_count != self.entry_count() as u8 { + return Err(TipRouterError::WeightMintsDoNotMatchLength); + } + + let table_mint_hash = Self::get_mint_hash(self.get_mints()); + if mint_hash != table_mint_hash { + return Err(TipRouterError::WeightMintsDoNotMatchMintHash); + } + + Ok(()) + } + pub fn entry_count(&self) -> usize { self.table.iter().filter(|entry| !entry.is_empty()).count() } - pub fn find_weight(&self, mint: &Pubkey) -> Option { + pub fn find_weight(&self, mint: &Pubkey) -> Option { self.table .iter() .find(|entry| entry.mint == *mint) .map(|entry| entry.weight) } - pub fn set_weight(&mut self, mint: &Pubkey, weight: PodU64) -> Result<(), TipRouterError> { - let entry = self - .table - .iter_mut() - .find(|entry| entry.mint == *mint || entry.is_empty()); - - match entry { - Some(entry) => { - entry.weight = weight; + pub fn set_weight(&mut self, mint: &Pubkey, weight: JitoNumber) -> Result<(), TipRouterError> { + // First, try to find an existing entry with the given mint + if let Some(entry) = self.table.iter_mut().find(|entry| entry.mint == *mint) { + entry.weight = weight; + return Ok(()); + } - if entry.mint == Pubkey::default() { - entry.mint = *mint; - } - } - None => return Err(TipRouterError::NoMoreTableSlots), + // If no existing entry found, look for the first empty slot + if let Some(entry) = self.table.iter_mut().find(|entry| entry.is_empty()) { + entry.mint = *mint; + entry.weight = weight; + return Ok(()); } - Ok(()) + // If no existing entry and no empty slots, return error + Err(TipRouterError::NoMoreTableSlots) + } + + pub const fn ncn(&self) -> Pubkey { + self.ncn + } + + pub fn ncn_epoch(&self) -> u64 { + self.ncn_epoch.into() } pub fn slot_created(&self) -> u64 { @@ -134,7 +178,7 @@ impl WeightTable { return Err(ProgramError::InvalidAccountOwner); } if weight_table.data_is_empty() { - msg!("Weight table is empty"); + msg!("Weight table account is empty"); return Err(ProgramError::InvalidAccountData); } if expect_writable && !weight_table.is_writable { @@ -158,18 +202,16 @@ impl WeightTable { #[repr(C)] pub struct WeightEntry { pub mint: Pubkey, - pub weight: PodU64, //TODO Change - // pub weight: Weight, + pub weight: JitoNumber, } impl WeightEntry { - pub const fn new(mint: Pubkey, weight: PodU64) -> Self { + pub const fn new(mint: Pubkey, weight: JitoNumber) -> Self { Self { weight, mint } } pub fn is_empty(&self) -> bool { - self.weight.eq(&PodU64::from(0)) - // self.weight.denominator() == 0 || self.mint.eq(&Pubkey::default()) + self.mint.eq(&Pubkey::default()) } } diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index 3c9eabf9..61b1bd5a 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -79,12 +79,8 @@ "type": "u64" }, { - "name": "weightNumerator", - "type": "u64" - }, - { - "name": "weightDenominator", - "type": "u64" + "name": "weight", + "type": "u128" } ], "discriminant": { @@ -120,6 +116,14 @@ { "name": "ncnEpoch", "type": "u64" + }, + { + "name": "mintHash", + "type": "u64" + }, + { + "name": "mintCount", + "type": "u8" } ], "discriminant": { @@ -185,6 +189,23 @@ } ], "types": [ + { + "name": "JitoNumber", + "type": { + "kind": "struct", + "fields": [ + { + "name": "value", + "type": { + "array": [ + "u8", + 16 + ] + } + } + ] + } + }, { "name": "WeightEntry", "type": { @@ -197,7 +218,7 @@ { "name": "weight", "type": { - "defined": "PodU64" + "defined": "JitoNumber" } } ] @@ -225,6 +246,16 @@ "name": "ModuloOverflow", "msg": "Modulo Overflow" }, + { + "code": 8451, + "name": "NewPreciseNumberError", + "msg": "New precise number error" + }, + { + "code": 8452, + "name": "CastToImpreciseNumberError", + "msg": "Cast to imprecise number error" + }, { "code": 8704, "name": "IncorrectWeightTableAdmin", @@ -234,6 +265,16 @@ "code": 8705, "name": "CannotCreateFutureWeightTables", "msg": "Cannnot create future weight tables" + }, + { + "code": 8706, + "name": "WeightMintsDoNotMatchLength", + "msg": "Weight mints do not match - length" + }, + { + "code": 8707, + "name": "WeightMintsDoNotMatchMintHash", + "msg": "Weight mints do not match - mint hash" } ], "metadata": { diff --git a/program/src/finalize_weight_table.rs b/program/src/finalize_weight_table.rs index 8e5a9f1d..76583c09 100644 --- a/program/src/finalize_weight_table.rs +++ b/program/src/finalize_weight_table.rs @@ -12,6 +12,8 @@ pub fn process_finalize_weight_table( program_id: &Pubkey, accounts: &[AccountInfo], ncn_epoch: u64, + mint_hash: u64, + mint_count: u8, ) -> ProgramResult { let [ncn, weight_table, weight_table_admin, restaking_program_id] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -19,10 +21,9 @@ pub fn process_finalize_weight_table( Ncn::load(restaking_program_id.key, ncn, false)?; let ncn_weight_table_admin = { - //TODO switch to weight table admin when that is merged let ncn_data = ncn.data.borrow(); let ncn = Ncn::try_from_slice_unchecked(&ncn_data)?; - ncn.admin + ncn.weight_table_admin }; load_signer(weight_table_admin, true)?; @@ -41,6 +42,8 @@ pub fn process_finalize_weight_table( let mut weight_table_data = weight_table.try_borrow_mut_data()?; let weight_table_account = WeightTable::try_from_slice_unchecked_mut(&mut weight_table_data)?; + weight_table_account.check_mints_okay(mint_hash, mint_count)?; + let current_slot = Clock::get()?.slot; weight_table_account.finalize(current_slot); diff --git a/program/src/lib.rs b/program/src/lib.rs index 39f150af..6f5f139b 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -59,26 +59,20 @@ pub fn process_instruction( // ------------------------------------------ // Update // ------------------------------------------ - WeightTableInstruction::UpdateWeightTable { - ncn_epoch, - weight_numerator, - weight_denominator, - } => { + WeightTableInstruction::UpdateWeightTable { ncn_epoch, weight } => { msg!("Instruction: UpdateWeightTable"); - process_update_weight_table( - program_id, - accounts, - ncn_epoch, - weight_numerator, - weight_denominator, - ) + process_update_weight_table(program_id, accounts, ncn_epoch, weight) } // ------------------------------------------ // Finalization // ------------------------------------------ - WeightTableInstruction::FinalizeWeightTable { ncn_epoch } => { + WeightTableInstruction::FinalizeWeightTable { + ncn_epoch, + mint_hash, + mint_count, + } => { msg!("Instruction: FinalizeWeightTable"); - process_finalize_weight_table(program_id, accounts, ncn_epoch) + process_finalize_weight_table(program_id, accounts, ncn_epoch, mint_hash, mint_count) } } } diff --git a/program/src/update_weight_table.rs b/program/src/update_weight_table.rs index aa9b1671..38080f52 100644 --- a/program/src/update_weight_table.rs +++ b/program/src/update_weight_table.rs @@ -1,7 +1,9 @@ -use jito_bytemuck::{types::PodU64, AccountDeserialize}; +use jito_bytemuck::AccountDeserialize; use jito_jsm_core::loader::{load_signer, load_token_mint}; use jito_restaking_core::ncn::Ncn; -use jito_tip_router_core::{error::TipRouterError, weight_table::WeightTable}; +use jito_tip_router_core::{ + error::TipRouterError, jito_number::JitoNumber, weight_table::WeightTable, +}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, pubkey::Pubkey, @@ -12,8 +14,7 @@ pub fn process_update_weight_table( program_id: &Pubkey, accounts: &[AccountInfo], ncn_epoch: u64, - weight_numerator: u64, - weight_denominator: u64, + weight: u128, ) -> ProgramResult { let [ncn, weight_table, weight_table_admin, mint, restaking_program_id] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -44,14 +45,7 @@ pub fn process_update_weight_table( let mut weight_table_data = weight_table.try_borrow_mut_data()?; let weight_table_account = WeightTable::try_from_slice_unchecked_mut(&mut weight_table_data)?; - weight_table_account.set_weight( - mint.key, - PodU64::from( - weight_numerator - .checked_div(weight_denominator) - .ok_or(TipRouterError::DenominatorIsZero)?, - ), - )?; + weight_table_account.set_weight(mint.key, JitoNumber::from_weight(weight))?; Ok(()) }