1use crate::error::AvmResult;
4use crate::types::{GlobalField, TealValue, TxnField};
5use std::collections::HashMap;
6
7pub type Address = Vec<u8>;
9
10pub type AppId = u64;
12
13pub type AssetId = u64;
15
16pub type MicroAlgos = u64;
18
19#[derive(Debug, Clone, PartialEq)]
21pub enum TransactionType {
22 Payment,
23 KeyRegistration,
24 AssetConfig,
25 AssetTransfer,
26 AssetFreeze,
27 ApplicationCall,
28 StateProof,
29}
30
31#[derive(Debug, Clone)]
33pub struct Transaction {
34 pub sender: Address,
35 pub fee: MicroAlgos,
36 pub first_valid: u64,
37 pub first_valid_time: u64,
38 pub last_valid: u64,
39 pub note: Vec<u8>,
40 pub lease: Vec<u8>,
41 pub receiver: Option<Address>,
42 pub amount: Option<MicroAlgos>,
43 pub close_remainder_to: Option<Address>,
44 pub vote_pk: Option<Vec<u8>>,
45 pub selection_pk: Option<Vec<u8>>,
46 pub vote_first: Option<u64>,
47 pub vote_last: Option<u64>,
48 pub vote_key_dilution: Option<u64>,
49 pub tx_type: TransactionType,
50 pub type_enum: u64,
51 pub xfer_asset: Option<AssetId>,
52 pub asset_amount: Option<u64>,
53 pub asset_sender: Option<Address>,
54 pub asset_receiver: Option<Address>,
55 pub asset_close_to: Option<Address>,
56 pub group_index: u64,
57 pub tx_id: Vec<u8>,
58 pub application_id: Option<AppId>,
59 pub on_completion: Option<u64>,
60 pub application_args: Vec<Vec<u8>>,
61 pub accounts: Vec<Address>,
62 pub approval_program: Option<Vec<u8>>,
63 pub clear_state_program: Option<Vec<u8>>,
64 pub rekey_to: Option<Address>,
65 pub config_asset: Option<AssetId>,
66 pub config_asset_total: Option<u64>,
67 pub config_asset_decimals: Option<u8>,
68 pub config_asset_default_frozen: Option<bool>,
69 pub config_asset_unit_name: Option<String>,
70 pub config_asset_name: Option<String>,
71 pub config_asset_url: Option<String>,
72 pub config_asset_metadata_hash: Option<Vec<u8>>,
73 pub config_asset_manager: Option<Address>,
74 pub config_asset_reserve: Option<Address>,
75 pub config_asset_freeze: Option<Address>,
76 pub config_asset_clawback: Option<Address>,
77 pub freeze_asset: Option<AssetId>,
78 pub freeze_asset_account: Option<Address>,
79 pub freeze_asset_frozen: Option<bool>,
80 pub assets: Vec<AssetId>,
81 pub applications: Vec<AppId>,
82 pub global_num_uint: Option<u64>,
83 pub global_num_byte_slice: Option<u64>,
84 pub local_num_uint: Option<u64>,
85 pub local_num_byte_slice: Option<u64>,
86 pub extra_program_pages: Option<u32>,
87 pub nonparticipation: Option<bool>,
88 pub logs: Vec<Vec<u8>>,
89 pub created_asset_id: Option<AssetId>,
90 pub created_application_id: Option<AppId>,
91 pub last_log: Option<Vec<u8>>,
92 pub state_proof_pk: Option<Vec<u8>>,
93 pub approval_program_pages: Vec<Vec<u8>>,
94 pub clear_state_program_pages: Vec<Vec<u8>>,
95}
96
97impl Default for Transaction {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl Transaction {
104 pub fn new() -> Self {
106 Self {
107 sender: vec![0; 32],
108 fee: 1000,
109 first_valid: 1,
110 first_valid_time: 0,
111 last_valid: 1000,
112 note: Vec::new(),
113 lease: vec![0; 32],
114 receiver: None,
115 amount: None,
116 close_remainder_to: None,
117 vote_pk: None,
118 selection_pk: None,
119 vote_first: None,
120 vote_last: None,
121 vote_key_dilution: None,
122 tx_type: TransactionType::Payment,
123 type_enum: 1,
124 xfer_asset: None,
125 asset_amount: None,
126 asset_sender: None,
127 asset_receiver: None,
128 asset_close_to: None,
129 group_index: 0,
130 tx_id: vec![0; 32],
131 application_id: None,
132 on_completion: None,
133 application_args: Vec::new(),
134 accounts: Vec::new(),
135 approval_program: None,
136 clear_state_program: None,
137 rekey_to: None,
138 config_asset: None,
139 config_asset_total: None,
140 config_asset_decimals: None,
141 config_asset_default_frozen: None,
142 config_asset_unit_name: None,
143 config_asset_name: None,
144 config_asset_url: None,
145 config_asset_metadata_hash: None,
146 config_asset_manager: None,
147 config_asset_reserve: None,
148 config_asset_freeze: None,
149 config_asset_clawback: None,
150 freeze_asset: None,
151 freeze_asset_account: None,
152 freeze_asset_frozen: None,
153 assets: Vec::new(),
154 applications: Vec::new(),
155 global_num_uint: None,
156 global_num_byte_slice: None,
157 local_num_uint: None,
158 local_num_byte_slice: None,
159 extra_program_pages: None,
160 nonparticipation: None,
161 logs: Vec::new(),
162 created_asset_id: None,
163 created_application_id: None,
164 last_log: None,
165 state_proof_pk: None,
166 approval_program_pages: Vec::new(),
167 clear_state_program_pages: Vec::new(),
168 }
169 }
170
171 pub fn payment(sender: Address, receiver: Address, amount: MicroAlgos) -> Self {
173 let mut tx = Self::new();
174 tx.sender = sender;
175 tx.receiver = Some(receiver);
176 tx.amount = Some(amount);
177 tx.tx_type = TransactionType::Payment;
178 tx.type_enum = 1;
179 tx
180 }
181
182 pub fn asset_transfer(
184 sender: Address,
185 receiver: Address,
186 asset_id: AssetId,
187 amount: u64,
188 ) -> Self {
189 let mut tx = Self::new();
190 tx.sender = sender;
191 tx.asset_receiver = Some(receiver);
192 tx.xfer_asset = Some(asset_id);
193 tx.asset_amount = Some(amount);
194 tx.tx_type = TransactionType::AssetTransfer;
195 tx.type_enum = 4;
196 tx
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct AssetHolding {
203 pub amount: u64,
204 pub frozen: bool,
205}
206
207#[derive(Debug, Clone)]
209pub struct AssetParams {
210 pub total: u64,
211 pub decimals: u8,
212 pub default_frozen: bool,
213 pub name: String,
214 pub unit_name: String,
215 pub url: String,
216 pub metadata_hash: Vec<u8>,
217 pub manager: Address,
218 pub reserve: Address,
219 pub freeze: Address,
220 pub clawback: Address,
221}
222
223#[derive(Debug, Clone)]
225pub struct AppParams {
226 pub approval_program: Vec<u8>,
227 pub clear_state_program: Vec<u8>,
228 pub global_state_schema: StateSchema,
229 pub local_state_schema: StateSchema,
230 pub extra_program_pages: u32,
231 pub creator: Address,
232}
233
234#[derive(Debug, Clone)]
236pub struct StateSchema {
237 pub num_uint: u64,
238 pub num_byte_slice: u64,
239}
240
241#[derive(Debug, Clone)]
243pub struct AccountParams {
244 pub micro_algos: MicroAlgos,
245 pub rewards_base: u64,
246 pub reward_algos: MicroAlgos,
247 pub status: String,
248 pub auth_addr: Option<Address>,
249 pub total_apps_schema: StateSchema,
250 pub total_apps_extra_pages: u32,
251 pub total_assets: u64,
252 pub total_created_assets: u64,
253 pub total_created_apps: u64,
254 pub total_boxes: u64,
255 pub total_box_bytes: u64,
256}
257
258pub trait LedgerAccess: std::fmt::Debug {
260 fn balance(&self, addr: &Address) -> AvmResult<MicroAlgos>;
262
263 fn min_balance(&self, addr: &Address) -> AvmResult<MicroAlgos>;
265
266 fn app_global_get(&self, app_id: AppId, key: &str) -> AvmResult<Option<TealValue>>;
268
269 fn app_global_put(&mut self, app_id: AppId, key: &str, value: TealValue) -> AvmResult<()>;
271
272 fn app_global_del(&mut self, app_id: AppId, key: &str) -> AvmResult<()>;
274
275 fn app_local_get(
277 &self,
278 addr: &Address,
279 app_id: AppId,
280 key: &str,
281 ) -> AvmResult<Option<TealValue>>;
282
283 fn app_local_put(
285 &mut self,
286 addr: &Address,
287 app_id: AppId,
288 key: &str,
289 value: TealValue,
290 ) -> AvmResult<()>;
291
292 fn app_local_del(&mut self, addr: &Address, app_id: AppId, key: &str) -> AvmResult<()>;
294
295 fn app_opted_in(&self, addr: &Address, app_id: AppId) -> AvmResult<bool>;
297
298 fn asset_holding(&self, addr: &Address, asset_id: AssetId) -> AvmResult<Option<AssetHolding>>;
300
301 fn asset_params(&self, asset_id: AssetId) -> AvmResult<Option<AssetParams>>;
303
304 fn app_params(&self, app_id: AppId) -> AvmResult<Option<AppParams>>;
306
307 fn account_params(&self, addr: &Address) -> AvmResult<Option<AccountParams>>;
309
310 fn current_round(&self) -> AvmResult<u64>;
312
313 fn latest_timestamp(&self) -> AvmResult<u64>;
315
316 fn genesis_hash(&self) -> AvmResult<Vec<u8>>;
318
319 fn current_application_id(&self) -> AvmResult<AppId>;
321
322 fn creator_address(&self) -> AvmResult<Address>;
324
325 fn current_application_address(&self) -> AvmResult<Address>;
327
328 fn group_id(&self) -> AvmResult<Vec<u8>>;
330
331 fn opcode_budget(&self) -> AvmResult<u64>;
333
334 fn caller_application_id(&self) -> AvmResult<Option<AppId>>;
336
337 fn caller_application_address(&self) -> AvmResult<Option<Address>>;
339
340 fn get_txn_field(&self, txn_index: usize, field: TxnField) -> AvmResult<TealValue>;
342
343 fn get_global_field(&self, field: GlobalField) -> AvmResult<TealValue>;
345
346 fn current_transaction(&self) -> AvmResult<Transaction>;
348
349 fn transaction_group(&self) -> AvmResult<Vec<Transaction>>;
351
352 fn program_args(&self) -> AvmResult<Vec<Vec<u8>>>;
354}
355
356#[derive(Debug)]
358pub struct MockLedger {
359 balances: HashMap<Address, MicroAlgos>,
360 min_balances: HashMap<Address, MicroAlgos>,
361 global_state: HashMap<(AppId, String), TealValue>,
362 local_state: HashMap<(Address, AppId, String), TealValue>,
363 opted_in: HashMap<(Address, AppId), bool>,
364 asset_holdings: HashMap<(Address, AssetId), AssetHolding>,
365 asset_params: HashMap<AssetId, AssetParams>,
366 app_params: HashMap<AppId, AppParams>,
367 account_params: HashMap<Address, AccountParams>,
368 current_round: u64,
369 latest_timestamp: u64,
370 genesis_hash: Vec<u8>,
371 current_app_id: AppId,
372 creator_addr: Address,
373 current_app_addr: Address,
374 group_id: Vec<u8>,
375 opcode_budget: u64,
376 caller_app_id: Option<AppId>,
377 caller_app_addr: Option<Address>,
378 transactions: Vec<Transaction>,
379 current_txn_index: usize,
380 program_args: Vec<Vec<u8>>,
381}
382
383impl MockLedger {
384 pub fn new() -> Self {
386 Self::default()
387 }
388
389 pub fn set_balance(&mut self, addr: Address, balance: MicroAlgos) {
391 self.balances.insert(addr, balance);
392 }
393
394 pub fn set_min_balance(&mut self, addr: Address, min_balance: MicroAlgos) {
396 self.min_balances.insert(addr, min_balance);
397 }
398
399 pub fn set_global_state(&mut self, app_id: AppId, key: String, value: TealValue) {
401 self.global_state.insert((app_id, key), value);
402 }
403
404 pub fn set_local_state(&mut self, addr: Address, app_id: AppId, key: String, value: TealValue) {
406 self.local_state.insert((addr, app_id, key), value);
407 }
408
409 pub fn set_opted_in(&mut self, addr: Address, app_id: AppId, opted_in: bool) {
411 self.opted_in.insert((addr, app_id), opted_in);
412 }
413
414 pub fn set_asset_holding(&mut self, addr: Address, asset_id: AssetId, holding: AssetHolding) {
416 self.asset_holdings.insert((addr, asset_id), holding);
417 }
418
419 pub fn set_asset_params(&mut self, asset_id: AssetId, params: AssetParams) {
421 self.asset_params.insert(asset_id, params);
422 }
423
424 pub fn set_app_params(&mut self, app_id: AppId, params: AppParams) {
426 self.app_params.insert(app_id, params);
427 }
428
429 pub fn set_account_params(&mut self, addr: Address, params: AccountParams) {
431 self.account_params.insert(addr, params);
432 }
433
434 pub fn set_current_round(&mut self, round: u64) {
436 self.current_round = round;
437 }
438
439 pub fn set_latest_timestamp(&mut self, timestamp: u64) {
441 self.latest_timestamp = timestamp;
442 }
443
444 pub fn set_genesis_hash(&mut self, hash: Vec<u8>) {
446 self.genesis_hash = hash;
447 }
448
449 pub fn set_current_application_id(&mut self, app_id: AppId) {
451 self.current_app_id = app_id;
452 }
453
454 pub fn set_creator_address(&mut self, addr: Address) {
456 self.creator_addr = addr;
457 }
458
459 pub fn set_current_application_address(&mut self, addr: Address) {
461 self.current_app_addr = addr;
462 }
463
464 pub fn set_group_id(&mut self, group_id: Vec<u8>) {
466 self.group_id = group_id;
467 }
468
469 pub fn set_opcode_budget(&mut self, budget: u64) {
471 self.opcode_budget = budget;
472 }
473
474 pub fn set_caller_application_id(&mut self, app_id: Option<AppId>) {
476 self.caller_app_id = app_id;
477 }
478
479 pub fn set_caller_application_address(&mut self, addr: Option<Address>) {
481 self.caller_app_addr = addr;
482 }
483
484 pub fn add_transaction(&mut self, transaction: Transaction) {
486 self.transactions.push(transaction);
487 }
488
489 pub fn set_current_transaction_index(&mut self, index: usize) {
491 self.current_txn_index = index;
492 }
493
494 pub fn set_program_args(&mut self, args: Vec<Vec<u8>>) {
496 self.program_args = args;
497 }
498
499 pub fn setup_payment_transaction(
501 &mut self,
502 sender: Address,
503 receiver: Address,
504 amount: MicroAlgos,
505 ) {
506 let tx = Transaction::payment(sender, receiver, amount);
507 self.transactions.clear();
508 self.transactions.push(tx);
509 self.current_txn_index = 0;
510 }
511
512 pub fn setup_asset_transfer(
514 &mut self,
515 sender: Address,
516 receiver: Address,
517 asset_id: AssetId,
518 amount: u64,
519 ) {
520 let tx = Transaction::asset_transfer(sender, receiver, asset_id, amount);
521 self.transactions.clear();
522 self.transactions.push(tx);
523 self.current_txn_index = 0;
524 }
525
526 pub fn clear_transactions(&mut self) {
528 self.transactions.clear();
529 self.current_txn_index = 0;
530 }
531
532 pub fn with_defaults() -> Self {
534 let mut ledger = Self {
535 balances: HashMap::new(),
536 min_balances: HashMap::new(),
537 global_state: HashMap::new(),
538 local_state: HashMap::new(),
539 opted_in: HashMap::new(),
540 asset_holdings: HashMap::new(),
541 asset_params: HashMap::new(),
542 app_params: HashMap::new(),
543 account_params: HashMap::new(),
544 current_round: 1000,
545 latest_timestamp: 1640995200, genesis_hash: vec![0; 32],
547 current_app_id: 0,
548 creator_addr: Vec::new(),
549 current_app_addr: Vec::new(),
550 group_id: Vec::new(),
551 opcode_budget: 700,
552 caller_app_id: None,
553 caller_app_addr: None,
554 transactions: Vec::new(),
555 current_txn_index: 0,
556 program_args: Vec::new(),
557 };
558
559 let sender = vec![1; 32];
561 let receiver = vec![2; 32];
562 ledger.setup_payment_transaction(sender, receiver, 1_000_000);
563
564 ledger
565 }
566}
567
568impl Default for MockLedger {
569 fn default() -> Self {
570 Self::with_defaults()
571 }
572}
573
574impl LedgerAccess for MockLedger {
575 fn balance(&self, addr: &Address) -> AvmResult<MicroAlgos> {
576 Ok(self.balances.get(addr).copied().unwrap_or(0))
577 }
578
579 fn min_balance(&self, addr: &Address) -> AvmResult<MicroAlgos> {
580 Ok(self.min_balances.get(addr).copied().unwrap_or(100000))
581 }
582
583 fn app_global_get(&self, app_id: AppId, key: &str) -> AvmResult<Option<TealValue>> {
584 Ok(self.global_state.get(&(app_id, key.to_string())).cloned())
585 }
586
587 fn app_global_put(&mut self, app_id: AppId, key: &str, value: TealValue) -> AvmResult<()> {
588 self.global_state.insert((app_id, key.to_string()), value);
589 Ok(())
590 }
591
592 fn app_global_del(&mut self, app_id: AppId, key: &str) -> AvmResult<()> {
593 self.global_state.remove(&(app_id, key.to_string()));
594 Ok(())
595 }
596
597 fn app_local_get(
598 &self,
599 addr: &Address,
600 app_id: AppId,
601 key: &str,
602 ) -> AvmResult<Option<TealValue>> {
603 Ok(self
604 .local_state
605 .get(&(addr.clone(), app_id, key.to_string()))
606 .cloned())
607 }
608
609 fn app_local_put(
610 &mut self,
611 addr: &Address,
612 app_id: AppId,
613 key: &str,
614 value: TealValue,
615 ) -> AvmResult<()> {
616 self.local_state
617 .insert((addr.clone(), app_id, key.to_string()), value);
618 Ok(())
619 }
620
621 fn app_local_del(&mut self, addr: &Address, app_id: AppId, key: &str) -> AvmResult<()> {
622 self.local_state
623 .remove(&(addr.clone(), app_id, key.to_string()));
624 Ok(())
625 }
626
627 fn app_opted_in(&self, addr: &Address, app_id: AppId) -> AvmResult<bool> {
628 Ok(self
629 .opted_in
630 .get(&(addr.clone(), app_id))
631 .copied()
632 .unwrap_or(false))
633 }
634
635 fn asset_holding(&self, addr: &Address, asset_id: AssetId) -> AvmResult<Option<AssetHolding>> {
636 Ok(self.asset_holdings.get(&(addr.clone(), asset_id)).cloned())
637 }
638
639 fn asset_params(&self, asset_id: AssetId) -> AvmResult<Option<AssetParams>> {
640 Ok(self.asset_params.get(&asset_id).cloned())
641 }
642
643 fn app_params(&self, app_id: AppId) -> AvmResult<Option<AppParams>> {
644 Ok(self.app_params.get(&app_id).cloned())
645 }
646
647 fn account_params(&self, addr: &Address) -> AvmResult<Option<AccountParams>> {
648 Ok(self.account_params.get(addr).cloned())
649 }
650
651 fn current_round(&self) -> AvmResult<u64> {
652 Ok(self.current_round)
653 }
654
655 fn latest_timestamp(&self) -> AvmResult<u64> {
656 Ok(self.latest_timestamp)
657 }
658
659 fn genesis_hash(&self) -> AvmResult<Vec<u8>> {
660 Ok(self.genesis_hash.clone())
661 }
662
663 fn current_application_id(&self) -> AvmResult<AppId> {
664 Ok(self.current_app_id)
665 }
666
667 fn creator_address(&self) -> AvmResult<Address> {
668 Ok(self.creator_addr.clone())
669 }
670
671 fn current_application_address(&self) -> AvmResult<Address> {
672 Ok(self.current_app_addr.clone())
673 }
674
675 fn group_id(&self) -> AvmResult<Vec<u8>> {
676 Ok(self.group_id.clone())
677 }
678
679 fn opcode_budget(&self) -> AvmResult<u64> {
680 Ok(self.opcode_budget)
681 }
682
683 fn caller_application_id(&self) -> AvmResult<Option<AppId>> {
684 Ok(self.caller_app_id)
685 }
686
687 fn caller_application_address(&self) -> AvmResult<Option<Address>> {
688 Ok(self.caller_app_addr.clone())
689 }
690
691 fn get_txn_field(&self, txn_index: usize, field: TxnField) -> AvmResult<TealValue> {
692 let tx = self.transactions.get(txn_index).ok_or_else(|| {
693 crate::error::AvmError::InvalidTransactionField {
694 field: format!("transaction index {txn_index}"),
695 }
696 })?;
697
698 let value = match field {
699 TxnField::Sender => TealValue::Bytes(tx.sender.clone()),
700 TxnField::Fee => TealValue::Uint(tx.fee),
701 TxnField::FirstValid => TealValue::Uint(tx.first_valid),
702 TxnField::FirstValidTime => TealValue::Uint(tx.first_valid_time),
703 TxnField::LastValid => TealValue::Uint(tx.last_valid),
704 TxnField::Note => TealValue::Bytes(tx.note.clone()),
705 TxnField::Lease => TealValue::Bytes(tx.lease.clone()),
706 TxnField::Receiver => TealValue::Bytes(tx.receiver.clone().unwrap_or_default()),
707 TxnField::Amount => TealValue::Uint(tx.amount.unwrap_or(0)),
708 TxnField::CloseRemainderTo => {
709 TealValue::Bytes(tx.close_remainder_to.clone().unwrap_or_default())
710 }
711 TxnField::VotePK => TealValue::Bytes(tx.vote_pk.clone().unwrap_or_default()),
712 TxnField::SelectionPK => TealValue::Bytes(tx.selection_pk.clone().unwrap_or_default()),
713 TxnField::VoteFirst => TealValue::Uint(tx.vote_first.unwrap_or(0)),
714 TxnField::VoteLast => TealValue::Uint(tx.vote_last.unwrap_or(0)),
715 TxnField::VoteKeyDilution => TealValue::Uint(tx.vote_key_dilution.unwrap_or(0)),
716 TxnField::Type => TealValue::Bytes(match tx.tx_type {
717 TransactionType::Payment => b"pay".to_vec(),
718 TransactionType::KeyRegistration => b"keyreg".to_vec(),
719 TransactionType::AssetConfig => b"acfg".to_vec(),
720 TransactionType::AssetTransfer => b"axfer".to_vec(),
721 TransactionType::AssetFreeze => b"afrz".to_vec(),
722 TransactionType::ApplicationCall => b"appl".to_vec(),
723 TransactionType::StateProof => b"stpf".to_vec(),
724 }),
725 TxnField::TypeEnum => TealValue::Uint(tx.type_enum),
726 TxnField::XferAsset => TealValue::Uint(tx.xfer_asset.unwrap_or(0)),
727 TxnField::AssetAmount => TealValue::Uint(tx.asset_amount.unwrap_or(0)),
728 TxnField::AssetSender => TealValue::Bytes(tx.asset_sender.clone().unwrap_or_default()),
729 TxnField::AssetReceiver => {
730 TealValue::Bytes(tx.asset_receiver.clone().unwrap_or_default())
731 }
732 TxnField::AssetCloseTo => {
733 TealValue::Bytes(tx.asset_close_to.clone().unwrap_or_default())
734 }
735 TxnField::GroupIndex => TealValue::Uint(tx.group_index),
736 TxnField::TxID => TealValue::Bytes(tx.tx_id.clone()),
737 TxnField::ApplicationID => TealValue::Uint(tx.application_id.unwrap_or(0)),
738 TxnField::OnCompletion => TealValue::Uint(tx.on_completion.unwrap_or(0)),
739 TxnField::ApplicationArgs => {
740 TealValue::Bytes(tx.application_args.first().cloned().unwrap_or_default())
742 }
743 TxnField::NumAppArgs => TealValue::Uint(tx.application_args.len() as u64),
744 TxnField::Accounts => {
745 TealValue::Bytes(tx.accounts.first().cloned().unwrap_or_default())
747 }
748 TxnField::NumAccounts => TealValue::Uint(tx.accounts.len() as u64),
749 TxnField::ApprovalProgram => {
750 TealValue::Bytes(tx.approval_program.clone().unwrap_or_default())
751 }
752 TxnField::ClearStateProgram => {
753 TealValue::Bytes(tx.clear_state_program.clone().unwrap_or_default())
754 }
755 TxnField::RekeyTo => TealValue::Bytes(tx.rekey_to.clone().unwrap_or_default()),
756 _ => TealValue::Uint(0), };
758
759 Ok(value)
760 }
761
762 fn get_global_field(&self, field: GlobalField) -> AvmResult<TealValue> {
763 let value = match field {
764 GlobalField::MinTxnFee => TealValue::Uint(1000),
765 GlobalField::MinBalance => TealValue::Uint(100000),
766 GlobalField::MaxTxnLife => TealValue::Uint(1000),
767 GlobalField::ZeroAddress => TealValue::Bytes(vec![0; 32]),
768 GlobalField::GroupSize => TealValue::Uint(self.transactions.len() as u64),
769 GlobalField::LogicSigVersion => TealValue::Uint(8),
770 GlobalField::Round => TealValue::Uint(self.current_round),
771 GlobalField::LatestTimestamp => TealValue::Uint(self.latest_timestamp),
772 GlobalField::CurrentApplicationID => TealValue::Uint(self.current_app_id),
773 GlobalField::CreatorAddress => TealValue::Bytes(self.creator_addr.clone()),
774 GlobalField::CurrentApplicationAddress => {
775 TealValue::Bytes(self.current_app_addr.clone())
776 }
777 GlobalField::GroupID => TealValue::Bytes(self.group_id.clone()),
778 GlobalField::OpcodeBudget => TealValue::Uint(self.opcode_budget),
779 GlobalField::CallerApplicationID => TealValue::Uint(self.caller_app_id.unwrap_or(0)),
780 GlobalField::CallerApplicationAddress => {
781 TealValue::Bytes(self.caller_app_addr.clone().unwrap_or_default())
782 }
783 GlobalField::GenesisHash => TealValue::Bytes(self.genesis_hash.clone()),
784 _ => TealValue::Uint(0), };
786
787 Ok(value)
788 }
789
790 fn current_transaction(&self) -> AvmResult<Transaction> {
791 self.transactions
792 .get(self.current_txn_index)
793 .cloned()
794 .ok_or_else(|| crate::error::AvmError::InvalidTransactionField {
795 field: format!("current transaction index {}", self.current_txn_index),
796 })
797 }
798
799 fn transaction_group(&self) -> AvmResult<Vec<Transaction>> {
800 Ok(self.transactions.clone())
801 }
802
803 fn program_args(&self) -> AvmResult<Vec<Vec<u8>>> {
804 Ok(self.program_args.clone())
805 }
806}