1use std::convert::TryInto;
2use stellar_rpc_client::{GetTransactionResponse, SimulateTransactionResponse};
3use stellar_xdr::curr::{
4 AccountEntry, AccountId, ContractEvent, ContractEventBody, ContractEventType, ContractEventV0,
5 ExtensionPoint, Hash, LedgerEntry, LedgerEntryChange, LedgerEntryData, LedgerEntryExt, Memo,
6 MuxedAccount, Operation, OperationBody, OperationMeta, OperationResult, Preconditions,
7 ScAddress, ScVal, SequenceNumber, SetOptionsOp, SorobanTransactionMeta,
8 SorobanTransactionMetaExt, Transaction, TransactionEnvelope, TransactionExt, TransactionMeta,
9 TransactionMetaV3, TransactionResult, TransactionResultExt, TransactionResultResult,
10 TransactionV1Envelope, Uint256, VecM,
11};
12
13use crate::SorobanTransactionResponse;
14
15pub struct MockTransactionResult {
16 pub success: bool,
17}
18
19pub struct MockTransactionMeta {
20 pub return_value: Option<ScVal>,
21 pub account_entry: Option<AccountEntry>,
22}
23
24pub struct MockGetTransactionResponse {
25 pub tx_result: Option<MockTransactionResult>,
26 pub tx_meta: Option<MockTransactionMeta>,
27 pub tx_envelope: Option<TransactionEnvelope>,
28}
29
30enum MockResponseType {
31 Basic,
32 WithReturnValue(ScVal),
33 WithAccountEntry(AccountEntry),
34}
35
36#[allow(dead_code)]
37pub fn mock_transaction(account_id: AccountId, operations: Vec<Operation>) -> Transaction {
38 Transaction {
39 fee: 100,
40 seq_num: SequenceNumber::from(1),
41 source_account: account_id.into(),
42 cond: Preconditions::None,
43 memo: Memo::None,
44 operations: operations.try_into().unwrap_or_default(),
45 ext: TransactionExt::V0,
46 }
47}
48
49#[allow(dead_code)]
50pub fn mock_transaction_envelope(account_id: AccountId) -> TransactionEnvelope {
51 TransactionEnvelope::Tx(TransactionV1Envelope {
52 tx: mock_transaction(account_id, vec![]),
53 signatures: Default::default(),
54 })
55}
56
57#[allow(dead_code)]
58pub fn create_contract_id_val() -> ScVal {
59 let contract_hash = Hash([1; 32]);
60 ScVal::Address(ScAddress::Contract(contract_hash))
61}
62
63#[allow(dead_code)]
64pub fn create_mock_set_options_tx_envelope() -> TransactionEnvelope {
65 let source_account = MuxedAccount::Ed25519(Uint256([0; 32]));
67
68 let set_options_op = Operation {
70 source_account: None,
71 body: OperationBody::SetOptions(SetOptionsOp {
72 inflation_dest: None,
73 clear_flags: None,
74 set_flags: None,
75 master_weight: None,
76 low_threshold: None,
77 med_threshold: None,
78 high_threshold: None,
79 home_domain: None,
80 signer: None,
81 }),
82 };
83
84 let operations = vec![set_options_op].try_into().unwrap_or_default();
86
87 TransactionEnvelope::Tx(TransactionV1Envelope {
89 tx: Transaction {
90 source_account,
91 fee: 100,
92 seq_num: 1.into(),
93 cond: Preconditions::None,
94 memo: Memo::None,
95 operations,
96 ext: TransactionExt::V0,
97 },
98 signatures: Default::default(),
99 })
100}
101
102#[allow(dead_code)]
103pub fn mock_simulate_tx_response(min_resource_fee: Option<u64>) -> SimulateTransactionResponse {
104 SimulateTransactionResponse {
105 min_resource_fee: min_resource_fee.unwrap_or(100),
106 transaction_data: "test".to_string(),
107 ..Default::default()
108 }
109}
110
111#[allow(dead_code)]
112fn mock_transaction_response_impl(response_type: MockResponseType) -> GetTransactionResponse {
113 let mut response = GetTransactionResponse {
114 status: "SUCCESS".to_string(),
115 envelope: None,
116 result: Some(create_success_tx_result()),
117 result_meta: None,
118 };
119
120 match response_type {
121 MockResponseType::Basic => {}
122 MockResponseType::WithReturnValue(val) => {
123 response.result_meta = Some(create_soroban_tx_meta_with_return_value(val));
124 }
125 MockResponseType::WithAccountEntry(account) => {
126 let ledger_entry = LedgerEntry {
127 last_modified_ledger_seq: 1,
128 data: LedgerEntryData::Account(account),
129 ext: LedgerEntryExt::V0,
130 };
131
132 let change = LedgerEntryChange::Updated(ledger_entry);
133 let changes = VecM::try_from(vec![change]).unwrap_or_default();
134 let op_meta = OperationMeta {
135 changes: stellar_xdr::curr::LedgerEntryChanges(changes),
136 };
137
138 let operations = VecM::try_from(vec![op_meta]).unwrap_or_default();
139 let meta = TransactionMeta::V3(TransactionMetaV3 {
140 ext: ExtensionPoint::V0,
141 soroban_meta: None,
142 tx_changes_before: Default::default(),
143 tx_changes_after: Default::default(),
144 operations,
145 });
146
147 response.result_meta = Some(meta);
148 }
149 }
150
151 response
152}
153
154#[allow(dead_code)]
155pub fn mock_transaction_response() -> SorobanTransactionResponse {
156 SorobanTransactionResponse::from(mock_transaction_response_impl(MockResponseType::Basic))
157}
158
159#[allow(dead_code)]
160pub fn mock_transaction_response_with_return_value(
161 return_val: ScVal,
162) -> SorobanTransactionResponse {
163 SorobanTransactionResponse::from(mock_transaction_response_impl(
164 MockResponseType::WithReturnValue(return_val),
165 ))
166}
167
168#[allow(dead_code)]
169pub fn mock_transaction_response_with_account_entry(
170 account: AccountEntry,
171) -> GetTransactionResponse {
172 mock_transaction_response_impl(MockResponseType::WithAccountEntry(account))
173}
174
175#[allow(dead_code)]
176fn create_success_tx_result() -> TransactionResult {
177 let empty_vec: Vec<OperationResult> = Vec::new();
179 let op_results = empty_vec.try_into().unwrap_or_default();
180
181 TransactionResult {
182 fee_charged: 100,
183 result: TransactionResultResult::TxSuccess(op_results),
184 ext: TransactionResultExt::V0,
185 }
186}
187
188#[allow(dead_code)]
189fn create_soroban_tx_meta_with_return_value(return_val: ScVal) -> TransactionMeta {
190 TransactionMeta::V3(TransactionMetaV3 {
191 ext: ExtensionPoint::V0,
192 soroban_meta: Some(SorobanTransactionMeta {
193 ext: SorobanTransactionMetaExt::V0,
194 events: Default::default(),
195 return_value: return_val,
196 diagnostic_events: Default::default(),
197 }),
198 tx_changes_before: Default::default(),
199 tx_changes_after: Default::default(),
200 operations: Default::default(),
201 })
202}
203
204#[allow(dead_code)]
205fn create_tx_meta_from_mock(mock: &MockTransactionMeta) -> TransactionMeta {
206 if let Some(return_val) = &mock.return_value {
208 return create_soroban_tx_meta_with_return_value(return_val.clone());
209 }
210
211 if let Some(account) = &mock.account_entry {
213 let ledger_entry = LedgerEntry {
215 last_modified_ledger_seq: 1,
216 data: LedgerEntryData::Account(account.clone()),
217 ext: LedgerEntryExt::V0,
218 };
219
220 let change = LedgerEntryChange::Updated(ledger_entry);
221 let changes = VecM::try_from(vec![change]).unwrap_or_default();
222 let op_meta = OperationMeta {
223 changes: stellar_xdr::curr::LedgerEntryChanges(changes),
224 };
225
226 let operations = VecM::try_from(vec![op_meta]).unwrap_or_default();
227
228 return TransactionMeta::V3(TransactionMetaV3 {
229 ext: ExtensionPoint::V0,
230 soroban_meta: None,
231 tx_changes_before: Default::default(),
232 tx_changes_after: Default::default(),
233 operations,
234 });
235 }
236
237 TransactionMeta::V3(TransactionMetaV3 {
239 ext: ExtensionPoint::V0,
240 soroban_meta: None,
241 tx_changes_before: Default::default(),
242 tx_changes_after: Default::default(),
243 operations: Default::default(),
244 })
245}
246
247#[allow(dead_code)]
248pub fn create_mock_contract_event() -> ContractEvent {
249 ContractEvent {
250 body: ContractEventBody::V0(ContractEventV0 {
251 data: ScVal::I32(0),
252 topics: VecM::default(),
253 }),
254 ext: ExtensionPoint::V0,
255 contract_id: Some(Hash([1; 32])),
256 type_: ContractEventType::Contract,
257 }
258}