Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ec6d05f
Accounts Refactor PR 2: Adding target_account
citizen-stig Apr 21, 2026
3d2d08a
Updating typescript to match new transaction
citizen-stig Apr 22, 2026
7bd74c9
Fixing typescript
citizen-stig Apr 22, 2026
3c7a41b
Continue fixing typescript
citizen-stig Apr 22, 2026
c0db317
Fixing lint
citizen-stig Apr 22, 2026
6f7486a
Updating README tests part 1
citizen-stig Apr 22, 2026
9c916ae
Documentation formatting
citizen-stig Apr 22, 2026
e440353
Addressing the feedback
citizen-stig Apr 22, 2026
56dac92
Fixes after rebase
citizen-stig May 4, 2026
acc4169
Fix after rebase
citizen-stig May 5, 2026
b008969
Simlify and fix
citizen-stig May 5, 2026
93392db
Rename target_address to address_override
citizen-stig May 5, 2026
fc22895
Address comments
citizen-stig May 5, 2026
5baef68
Keep fixing
citizen-stig May 5, 2026
3ed08db
More cleaning up
citizen-stig May 5, 2026
ce7b152
More cleaning up
citizen-stig May 6, 2026
e95e15e
Reformat comments
citizen-stig May 6, 2026
e0fb2e9
Regenrate rollup_resync and start updating readme tests
citizen-stig May 6, 2026
06910e7
Bring back account_2
citizen-stig May 6, 2026
3544ca4
Addressing feedback
citizen-stig May 6, 2026
d227aa5
Update EIP-712 tests
citizen-stig May 6, 2026
a13d670
More typescript clean ups and comments
citizen-stig May 6, 2026
7a3675e
Fixes
citizen-stig May 6, 2026
ee95477
More fixes
citizen-stig May 6, 2026
4cf1394
update hyperlane image so tests are suppose to pass
citizen-stig May 7, 2026
fffe0a5
Lint!
citizen-stig May 7, 2026
bb7601d
use lander based image
citizen-stig May 7, 2026
37c05ab
Update crates/module-system/sov-modules-api/src/transaction/types/v0.rs
citizen-stig May 8, 2026
84b0e9f
Update crates/module-system/sov-modules-api/src/transaction/types/v1.rs
citizen-stig May 8, 2026
f005650
Update crates/module-system/sov-solana-offchain-auth/src/authenticati…
citizen-stig May 8, 2026
65158b8
Update crates/module-system/sov-solana-offchain-auth/src/authenticati…
citizen-stig May 8, 2026
a813c44
Update crates/module-system/sov-modules-api/src/transaction/unsigned/…
citizen-stig May 8, 2026
fa2c17b
Update crates/module-system/sov-modules-api/src/transaction/unsigned/…
citizen-stig May 8, 2026
425a029
Addressing feedback
citizen-stig May 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/full-node/sov-api-spec/openapi-v3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,10 @@ components:
type: object
description: Optional uniqueness data for the transaction
additionalProperties: true
address_override:
type: string
nullable: true
description: Optional address override for execution; null uses default routing
required:
- sender
- call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ fn create_insert_credentials(
max_fee,
UniquenessData::Nonce(nonce),
gas_limit,
None,
),
)
}
Expand Down
23 changes: 18 additions & 5 deletions crates/full-node/sov-rollup-apis/src/endpoints/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,23 +304,34 @@ impl<S: Spec, R: Runtime<S>> SovereignSimulate<S, R> {
&self,
params: &SimulateParameters,
state: &mut StateCheckpoint<S>,
) -> AuthorizationData<S> {
let credential_id = CredentialId::from_str(&params.sender).unwrap();
) -> Result<AuthorizationData<S>, SimulateError> {
let credential_id = CredentialId::from_str(&params.sender).map_err(|e| {
SimulateError::InvalidInput(format!("failed to parse sender credential id: {e:?}"))
})?;
let address_override = params
.address_override
.as_deref()
.map(S::Address::from_str)
.transpose()
.map_err(|e| {
SimulateError::InvalidInput(format!("failed to parse address override: {e:?}"))
})?;
let uniqueness = params.uniqueness.unwrap_or_else(|| {
let generation = Uniqueness::<S>::default()
.next_generation(&credential_id, state)
.unwrap();
UniquenessData::Generation(generation)
});

AuthorizationData {
Ok(AuthorizationData {
tx_hash: NULL_TX_HASH,
non_malleable_hash: NULL_TX_HASH,
uniqueness,
credential_id,
default_address: credential_id.into(),
credentials: Credentials::new(credential_id),
}
address_override,
})
}

fn outcome(&self, result: ApplyTxResult<S>) -> SimulateOutcome<R::RuntimeEvent> {
Expand Down Expand Up @@ -402,6 +413,8 @@ pub struct SimulateParameters {
/// Optional uniqueness data for the transaction.
/// If not provided a valid uniqueness will be used.
pub uniqueness: Option<UniquenessData>,
/// Optional address override for execution; null uses default routing.
pub address_override: Option<String>,
}

impl<S: Spec, R: Runtime<S>> SimulateEndpoint for SovereignSimulate<S, R> {
Expand All @@ -427,7 +440,7 @@ impl<S: Spec, R: Runtime<S>> SimulateEndpoint for SovereignSimulate<S, R> {
.chain_state()
.base_fee_per_gas(&mut accessor)
.ok_or(SimulateError::GasPriceRetrieval)?;
let auth_data = state.authorization_data(&params, &mut accessor);
let auth_data = state.authorization_data(&params, &mut accessor)?;
let sequencer = state.sequencer(params.sequencer.unwrap_or_default())?;
let auth_tx_data =
AuthenticatedTransactionData(state.tx_details(params.tx_details.unwrap_or_default())?);
Expand Down
93 changes: 91 additions & 2 deletions crates/full-node/sov-rollup-apis/tests/integration/rest_api.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use sov_api_spec::types;
use sov_bank::{config_gas_token_id, Bank};
use sov_modules_api::prelude::tokio::{self};
use sov_modules_api::{Amount, Gas, GasArray, GasSpec, Spec};
use sov_modules_api::sov_universal_wallet::schema::RollupRoots;
use sov_modules_api::{
get_runtime_schema, Amount, CredentialId, Gas, GasArray, GasSpec, Runtime, Spec,
};
use sov_rest_utils::json_obj;
use sov_rollup_interface::node::SyncStatus;
use sov_test_utils::{AsUser, TestUser, TransactionTestCase};
use sov_test_utils::{
default_test_tx_details, AsUser, TestUser, TransactionTestCase, TransactionType,
};

use crate::{TestData, RT, S};

Expand Down Expand Up @@ -167,6 +172,90 @@ async fn test_simulation_success() {
);
}

#[tokio::test(flavor = "multi_thread")]
async fn test_simulation_success_with_address_override() {
let mut data = TestData::setup().await;
let delegated_credential: CredentialId = [9u8; 32].into();
let registration_call = json_obj!({
"accounts": {
"insert_credential_id": delegated_credential,
},
});
let schema = get_runtime_schema::<S, RT>().unwrap();
let registration_call_bytes = schema
.json_to_borsh(
schema
.rollup_expected_index(RollupRoots::RuntimeCall)
.unwrap(),
&serde_json::to_string(&registration_call).unwrap(),
)
.unwrap();

data.runner.execute_transaction(TransactionTestCase {
input: TransactionType::Plain {
message: RT::decode_call(&registration_call_bytes).unwrap(),
key: data.user.private_key().clone(),
details: default_test_tx_details::<S>(),
},
assert: Box::new(move |result, _state| {
assert!(
result.tx_receipt.is_successful(),
"The credential registration should have succeeded"
);
}),
});
data.send_storage();

let address_override = data.user.address();
let receiver = TestUser::<S>::generate_with_default_balance().address();
let call = sov_bank::CallMessage::<S>::Transfer {
to: receiver,
coins: sov_bank::Coins {
amount: Amount::new(1000),
token_id: config_gas_token_id(),
},
};
let params = json_obj!({
"sender": delegated_credential.to_string(),
"address_override": address_override.to_string(),
"call": {
"bank": call,
},
});
let client = reqwest::Client::new();

let response = client
.post(format!("http://{}/rollup/simulate", data.axum_addr))
.json(&params)
.send()
.await
.unwrap();
let actual = response.json::<serde_json::Value>().await.unwrap();

assert_eq!(actual["outcome"], "success");
assert_eq!(
actual["events"][0],
serde_json::json!({
"key": "Bank/TokenTransferred",
"module": "Bank",
"value": {
"token_transferred": {
"from": {
"user": address_override
},
"to": {
"user": receiver
},
"coins": {
"amount": "1000",
"token_id": "token_1nyl0e0yweragfsatygt24zmd8jrr2vqtvdfptzjhxkguz2xxx3vs0y07u7"
}
}
}
})
);
}

#[tokio::test(flavor = "multi_thread")]
async fn test_simulation_fail() {
let data = TestData::setup().await;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async fn test_mixed_nonce_and_generation_transactions() {

let construct_tx = |uniqueness: UniquenessData| {
let unsigned_tx =
UnsignedTransactionV0::new_with_details(msg.clone(), uniqueness, details.clone());
UnsignedTransactionV0::new_with_details(msg.clone(), uniqueness, details.clone(), None);
Transaction::<RT, TestSpec>::new_signed_tx(
&test_user.private_key,
&RT::CHAIN_HASH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,10 @@ impl HyperlaneBuilder {
let docker_image = env::var("CUSTOM_HLP_DOCKER_IMAGE");
let has_custom_image = !matches!(docker_image, Err(env::VarError::NotPresent));

// Current image is based on https://github.com/Sovereign-Labs/hyperlane-monorepo/tree/sovereign-lander-integration
let docker_image = docker_image
.unwrap_or_else(|_| "ghcr.io/theodorebugnet/hyperlane-agent:multisig_upgrade".into());
// Current image is based on https://github.com/Sovereign-Labs/hyperlane-monorepo/tree/sovereign-lander-integration-for-multisig
let docker_image = docker_image.unwrap_or_else(|_| {
"ghcr.io/citizen-stig/hyperlane-agent:multisig-upgrade-address-override-2".into()
});
let (name, tag) = docker_image
.split_once(':')
.unwrap_or((&docker_image, "latest"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use sov_test_utils::runtime::{config_gas_token_id, Payable, TestRunner};

type S = sov_test_utils::TestSpec;

use sov_modules_api::transaction::{Transaction, TxDetails, UnsignedTransactionV0};
use sov_modules_api::transaction::{Transaction, TxDetails, UnsignedTransactionV0, Version0};
use sov_modules_api::{PrivateKey, RawTx};
use sov_test_utils::{EncodeCall, TestUser, TEST_DEFAULT_MAX_FEE};
use sov_value_setter::ValueSetter;
Expand Down Expand Up @@ -243,6 +243,7 @@ pub fn create_tx_bad_sig<RT: Runtime<S>>(
TEST_DEFAULT_MAX_FEE,
UniquenessData::Nonce(nonce),
None,
None,
);

let signed_tx = Transaction::<RT, S>::new_signed_tx(&signer.private_key, &RT::CHAIN_HASH, utx);
Expand All @@ -251,18 +252,19 @@ pub fn create_tx_bad_sig<RT: Runtime<S>>(
let bad_signature = signer.private_key.sign(&[1, 2, 3]);

match signed_tx {
Transaction::V0(inner) => Transaction::new_with_details_v0(
inner.pub_key,
inner.runtime_call,
bad_signature,
inner.uniqueness,
TxDetails {
Transaction::V0(inner) => Transaction::V0(Version0 {
signature: bad_signature,
pub_key: inner.pub_key,
runtime_call: inner.runtime_call,
uniqueness: inner.uniqueness,
details: TxDetails {
max_priority_fee_bips,
max_fee: Amount::new(200_000),
gas_limit: None,
chain_id,
},
),
address_override: inner.address_override,
}),
Transaction::V1(_inner) => {
todo!("Bad signature generation for multisig transactions is not yet supported");
}
Expand All @@ -283,6 +285,7 @@ pub fn create_tx_bad_sender<RT: Runtime<S>>(
Amount::new(200_000),
UniquenessData::Nonce(nonce),
None,
None,
);

let signer = TestUser::<S>::generate(Amount::ZERO);
Expand All @@ -303,6 +306,7 @@ pub fn create_tx_valid<RT: Runtime<S>>(
TEST_DEFAULT_MAX_FEE,
UniquenessData::Generation(generation),
None,
None,
);

Transaction::<RT, S>::new_signed_tx(signer.private_key(), &RT::CHAIN_HASH, utx)
Expand All @@ -323,6 +327,7 @@ pub fn create_tx_out_of_gas<RT: Runtime<S>>(
Amount::new(200_000),
UniquenessData::Nonce(nonce),
Some(<<S as Spec>::Gas as Gas>::zero()),
None,
);

Transaction::<RT, S>::new_signed_tx(signer.private_key(), &RT::CHAIN_HASH, utx)
Expand Down
Loading
Loading