diff --git a/Cargo.lock b/Cargo.lock index 00bf8bce7125a..9607ffeb9ea3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2918,6 +2918,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "copy_dir" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "543d1dd138ef086e2ff05e3a48cf9da045da2033d16f8538fd76b86cd49b2ca3" +dependencies = [ + "walkdir", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -6667,6 +6676,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +[[package]] +name = "libquickjs-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0b24e9bd171b75ae0295bd428fb8fe58410fb23156e5f34a4657a70c3cee96" +dependencies = [ + "cc", + "copy_dir", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -10295,6 +10314,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-js" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19cb4cefcb00f4ab9b332664d06005a74f582ac16aa959c6ad5912957bd83e5f" +dependencies = [ + "libquickjs-sys", + "once_cell", +] + [[package]] name = "quick-xml" version = "0.36.1" @@ -14565,6 +14594,7 @@ dependencies = [ "move-core-types", "mysten-metrics", "once_cell", + "quick-js", "rand 0.8.5", "reqwest 0.12.5", "serde", diff --git a/crates/sui-rosetta/Cargo.toml b/crates/sui-rosetta/Cargo.toml index e68a394b172e4..dbf36f99d556c 100644 --- a/crates/sui-rosetta/Cargo.toml +++ b/crates/sui-rosetta/Cargo.toml @@ -51,3 +51,4 @@ tempfile.workspace = true rand.workspace = true reqwest.workspace = true move-cli.workspace = true +quick-js = "0.4.1" diff --git a/crates/sui-rosetta/src/construction.rs b/crates/sui-rosetta/src/construction.rs index 97265f9ab62cc..b39dbc99c4795 100644 --- a/crates/sui-rosetta/src/construction.rs +++ b/crates/sui-rosetta/src/construction.rs @@ -386,7 +386,7 @@ pub async fn metadata( sender, coins, objects, - total_coin_value, + total_coin_value: total_coin_value.into(), gas_price, budget, currency, diff --git a/crates/sui-rosetta/src/types.rs b/crates/sui-rosetta/src/types.rs index 57d906efd9a2b..2d499a494767f 100644 --- a/crates/sui-rosetta/src/types.rs +++ b/crates/sui-rosetta/src/types.rs @@ -663,7 +663,8 @@ pub struct ConstructionMetadata { pub sender: SuiAddress, pub coins: Vec, pub objects: Vec, - pub total_coin_value: u64, + #[serde(with = "str_format")] + pub total_coin_value: i128, pub gas_price: u64, pub budget: u64, pub currency: Option, @@ -987,7 +988,8 @@ impl InternalOperation { let state = builder.input(CallArg::SUI_SYSTEM_MUT)?; (validator, state, amount) } else { - let amount = builder.pure(metadata.total_coin_value - metadata.budget)?; + let amount = + builder.pure(metadata.total_coin_value as u64 - metadata.budget)?; let state = builder.input(CallArg::SUI_SYSTEM_MUT)?; let validator = builder.input(CallArg::Pure(bcs::to_bytes(&validator)?))?; (validator, state, amount) diff --git a/crates/sui-rosetta/src/unit_tests/types_tests.rs b/crates/sui-rosetta/src/unit_tests/types_tests.rs index 72b66b986c309..d55aa6cd1d307 100644 --- a/crates/sui-rosetta/src/unit_tests/types_tests.rs +++ b/crates/sui-rosetta/src/unit_tests/types_tests.rs @@ -1,7 +1,12 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::types::{AccountBalanceRequest, Amount, Currency, CurrencyMetadata}; +use crate::types::{ + AccountBalanceRequest, Amount, ConstructionMetadata, Currency, CurrencyMetadata, +}; +use quick_js::Context; +use serde::{Deserialize, Serialize}; use serde_json::json; +use sui_types::base_types::{ObjectRef, SuiAddress}; #[tokio::test] async fn test_currency_defaults() { @@ -65,3 +70,56 @@ async fn test_currency_defaults() { account_balance_request.currencies.0.clone().pop().unwrap() ); } + +#[tokio::test] +async fn test_metadata_total_coin_value_js_conversion_for_large_balance() { + #[derive(Serialize, Deserialize, Debug)] + pub struct TestConstructionMetadata { + pub sender: SuiAddress, + pub coins: Vec, + pub objects: Vec, + pub total_coin_value: u64, + pub gas_price: u64, + pub budget: u64, + pub currency: Option, + } + + let test_metadata = TestConstructionMetadata { + sender: Default::default(), + coins: vec![], + objects: vec![], + total_coin_value: 65_000_004_233_578_496, + gas_price: 0, + budget: 0, + currency: None, + }; + let test_metadata_json = serde_json::to_string(&test_metadata).unwrap(); + + let prod_metadata = ConstructionMetadata { + sender: Default::default(), + coins: vec![], + objects: vec![], + total_coin_value: 65_000_004_233_578_496, + gas_price: 0, + budget: 0, + currency: None, + }; + let prod_metadata_json = serde_json::to_string(&prod_metadata).unwrap(); + + let context = Context::new().unwrap(); + + let test_total_coin_value = format!( + "JSON.parse({:?}).total_coin_value.toString()", + test_metadata_json + ); + let js_test_total_coin_value = context.eval_as::(&test_total_coin_value).unwrap(); + + let prod_total_coin_value = format!( + "JSON.parse({:?}).total_coin_value.toString()", + prod_metadata_json + ); + let js_prod_total_coin_value = context.eval_as::(&prod_total_coin_value).unwrap(); + + assert_eq!("65000004233578500", js_test_total_coin_value); + assert_eq!("65000004233578496", js_prod_total_coin_value); +}