Skip to content

Commit fb8f3d4

Browse files
authored
Merge pull request #188 from algorandfoundation/fix/msg-pack
fix: encoding asset freeze
2 parents c4918eb + 9502c7a commit fb8f3d4

File tree

5 files changed

+1738
-1242
lines changed

5 files changed

+1738
-1242
lines changed

crates/algokit_transact/src/test_utils/mod.rs

Lines changed: 65 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -160,113 +160,88 @@ impl TransactionMother {
160160
}
161161

162162
pub fn asset_freeze() -> AssetFreezeTransactionBuilder {
163-
AssetFreezeTransactionBuilder::default()
164-
.header(TransactionHeaderMother::simple_testnet().build().unwrap())
165-
.asset_id(12345)
166-
.freeze_target(AddressMother::neil())
167-
.frozen(true)
168-
.to_owned()
169-
}
170-
171-
pub fn asset_unfreeze() -> AssetFreezeTransactionBuilder {
172-
AssetFreezeTransactionBuilder::default()
173-
.header(TransactionHeaderMother::simple_testnet().build().unwrap())
174-
.asset_id(12345)
175-
.freeze_target(AddressMother::neil())
176-
.frozen(false)
177-
.to_owned()
178-
}
163+
// mainnet-2XFGVOHMFYLAWBHOSIOI67PBT5LDRHBTD3VLX5EYBDTFNVKMCJIA
164+
let sender = "E4A6FVIHXSZ3F7QXRCOTYDDILVQYEBFH56HYDIIYX4SVXS2QX5GUTBVZHY"
165+
.parse::<Address>()
166+
.unwrap();
167+
let freeze_address = "ZJU3X2B2QN3BUBIJ64JZ565V363ANGBUDOLXAJHDXGIIMYK6WV3NSNCBQQ"
168+
.parse::<Address>()
169+
.unwrap();
170+
let genesis_hash: Byte32 = BASE64_STANDARD
171+
.decode("wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=")
172+
.unwrap()
173+
.try_into()
174+
.unwrap();
175+
let note = BASE64_STANDARD
176+
.decode("TkZUIGZyZWV6ZWQgYnkgbG9mdHkuYWk=")
177+
.unwrap();
178+
let group = BASE64_STANDARD
179+
.decode("xERjxVTlNb8jeHa16qmpxDMh4+dcDCokO69QnNESbFk=")
180+
.unwrap()
181+
.try_into()
182+
.unwrap();
179183

180-
pub fn asset_freeze_mainnet() -> AssetFreezeTransactionBuilder {
181-
// Based on a real mainnet asset freeze transaction
182-
// https://algoexplorer.io/tx/EXAMPLE_FREEZE_TXN_ID
183184
AssetFreezeTransactionBuilder::default()
184185
.header(
185-
TransactionHeaderMother::mainnet()
186-
.sender(AddressMother::address())
187-
.first_valid(39000000)
188-
.last_valid(39001000)
186+
TransactionHeaderBuilder::default()
187+
.sender(sender)
189188
.fee(1000)
189+
.first_valid(37463562)
190+
.last_valid(37464562)
191+
.genesis_hash(genesis_hash)
192+
.genesis_id("mainnet-v1.0".to_string())
193+
.note(note)
194+
.group(group)
190195
.build()
191196
.unwrap(),
192197
)
193-
.asset_id(31566704) // USDC on mainnet
194-
.freeze_target(AddressMother::neil())
198+
.asset_id(1707148495)
199+
.freeze_target(freeze_address)
195200
.frozen(true)
196201
.to_owned()
197202
}
198203

199-
pub fn asset_freeze_testnet() -> AssetFreezeTransactionBuilder {
200-
// Based on a real testnet asset freeze transaction
201-
AssetFreezeTransactionBuilder::default()
202-
.header(
203-
TransactionHeaderMother::testnet()
204-
.sender(AddressMother::address())
205-
.first_valid(42000000)
206-
.last_valid(42001000)
207-
.fee(1000)
208-
.note(BASE64_STANDARD.decode("VGVzdCBhc3NldCBmcmVlemU=").unwrap())
209-
.build()
210-
.unwrap(),
211-
)
212-
.asset_id(150000000) // Test asset on testnet
213-
.freeze_target(AddressMother::neil())
214-
.frozen(true)
215-
.to_owned()
216-
}
204+
pub fn asset_unfreeze() -> AssetFreezeTransactionBuilder {
205+
// Same as asset_freeze but with frozen=false
206+
let sender = "E4A6FVIHXSZ3F7QXRCOTYDDILVQYEBFH56HYDIIYX4SVXS2QX5GUTBVZHY"
207+
.parse::<Address>()
208+
.unwrap();
209+
let freeze_address = "ZJU3X2B2QN3BUBIJ64JZ565V363ANGBUDOLXAJHDXGIIMYK6WV3NSNCBQQ"
210+
.parse::<Address>()
211+
.unwrap();
212+
let genesis_hash: Byte32 = BASE64_STANDARD
213+
.decode("wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=")
214+
.unwrap()
215+
.try_into()
216+
.unwrap();
217+
let note = BASE64_STANDARD
218+
.decode("TkZUIGZyZWV6ZWQgYnkgbG9mdHkuYWk=")
219+
.unwrap();
220+
let group = BASE64_STANDARD
221+
.decode("xERjxVTlNb8jeHa16qmpxDMh4+dcDCokO69QnNESbFk=")
222+
.unwrap()
223+
.try_into()
224+
.unwrap();
217225

218-
pub fn asset_unfreeze_mainnet() -> AssetFreezeTransactionBuilder {
219-
// Based on a real mainnet asset unfreeze transaction
220226
AssetFreezeTransactionBuilder::default()
221227
.header(
222-
TransactionHeaderMother::mainnet()
223-
.sender(AddressMother::address())
224-
.first_valid(39002000)
225-
.last_valid(39003000)
228+
TransactionHeaderBuilder::default()
229+
.sender(sender)
226230
.fee(1000)
231+
.first_valid(37463562)
232+
.last_valid(37464562)
233+
.genesis_hash(genesis_hash)
234+
.genesis_id("mainnet-v1.0".to_string())
235+
.note(note)
236+
.group(group)
227237
.build()
228238
.unwrap(),
229239
)
230-
.asset_id(31566704) // USDC on mainnet
231-
.freeze_target(AddressMother::neil())
240+
.asset_id(1707148495)
241+
.freeze_target(freeze_address)
232242
.frozen(false)
233243
.to_owned()
234244
}
235-
236-
pub fn asset_freeze_with_group() -> AssetFreezeTransactionBuilder {
237-
// Asset freeze transaction as part of a group
238-
AssetFreezeTransactionBuilder::default()
239-
.header(
240-
TransactionHeaderMother::testnet()
241-
.sender(AddressMother::address())
242-
.first_valid(21000000)
243-
.last_valid(21001000)
244-
.fee(1000)
245-
.group(
246-
BASE64_STANDARD
247-
.decode("VZOPGVBJhOB3AiX8mqxKb7FQD1faupdSuZixhd8xpqI=")
248-
.unwrap()
249-
.try_into()
250-
.unwrap(),
251-
)
252-
.build()
253-
.unwrap(),
254-
)
255-
.asset_id(84366776)
256-
.freeze_target(AddressMother::neil())
257-
.frozen(true)
258-
.to_owned()
259-
}
260-
261-
pub fn asset_freeze_minimal() -> AssetFreezeTransactionBuilder {
262-
// Minimal asset freeze with only required fields
263-
AssetFreezeTransactionBuilder::default()
264-
.header(TransactionHeaderMother::simple_testnet().build().unwrap())
265-
.asset_id(1)
266-
.freeze_target(AddressMother::zero_address())
267-
.frozen(true)
268-
.to_owned()
269-
}
270245
}
271246

272247
pub struct AddressMother {}
@@ -720,10 +695,9 @@ mod tests {
720695
#[test]
721696
fn test_asset_freeze_snapshot() {
722697
let data = TestDataMother::asset_freeze();
723-
// Note: These values would need to be updated once we run the actual test
724-
// to get the real encoded transaction values
725-
assert!(!data.id.is_empty());
726-
assert!(!data.unsigned_bytes.is_empty());
727-
assert!(!data.signed_bytes.is_empty());
698+
assert_eq!(
699+
data.id,
700+
String::from("2XFGVOHMFYLAWBHOSIOI67PBT5LDRHBTD3VLX5EYBDTFNVKMCJIA")
701+
);
728702
}
729703
}

crates/algokit_transact/src/tests.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ fn test_asset_unfreeze_transaction_encoding() {
446446
let asset_freeze_tx = tx_builder.build().unwrap();
447447

448448
// Verify it's an unfreeze transaction
449-
assert_eq!(asset_freeze_tx_fields.frozen, false);
449+
assert_eq!(asset_freeze_tx_fields.frozen, Some(false));
450450

451451
let encoded = asset_freeze_tx.encode().unwrap();
452452
let decoded = Transaction::decode(&encoded).unwrap();
@@ -530,8 +530,8 @@ fn test_asset_freeze_vs_unfreeze() {
530530
let freeze_tx = TransactionMother::asset_freeze().build_fields().unwrap();
531531
let unfreeze_tx = TransactionMother::asset_unfreeze().build_fields().unwrap();
532532

533-
assert_eq!(freeze_tx.frozen, true);
534-
assert_eq!(unfreeze_tx.frozen, false);
533+
assert_eq!(freeze_tx.frozen, Some(true));
534+
assert_eq!(unfreeze_tx.frozen, Some(false));
535535
assert_eq!(freeze_tx.asset_id, unfreeze_tx.asset_id);
536536
assert_eq!(freeze_tx.freeze_target, unfreeze_tx.freeze_target);
537537
}
@@ -551,15 +551,15 @@ fn test_asset_freeze_builder_validation() {
551551
if let Transaction::AssetFreeze(fields) = tx {
552552
assert_eq!(fields.asset_id, 12345);
553553
assert_eq!(fields.freeze_target, AddressMother::neil());
554-
assert_eq!(fields.frozen, true);
554+
assert_eq!(fields.frozen, Some(true));
555555
} else {
556556
panic!("Expected AssetFreeze transaction");
557557
}
558558
}
559559

560560
#[test]
561561
fn test_asset_freeze_mainnet_encoding() {
562-
let tx = TransactionMother::asset_freeze_mainnet().build().unwrap();
562+
let tx = TransactionMother::asset_freeze().build().unwrap();
563563
// Just verify it encodes without checking exact size
564564
let encoded = tx.encode().unwrap();
565565
let decoded = Transaction::decode(&encoded).unwrap();
@@ -568,7 +568,7 @@ fn test_asset_freeze_mainnet_encoding() {
568568

569569
#[test]
570570
fn test_asset_freeze_testnet_encoding() {
571-
let tx = TransactionMother::asset_freeze_testnet().build().unwrap();
571+
let tx = TransactionMother::asset_freeze().build().unwrap();
572572
// Just verify it encodes without checking exact size
573573
let encoded = tx.encode().unwrap();
574574
let decoded = Transaction::decode(&encoded).unwrap();
@@ -577,15 +577,16 @@ fn test_asset_freeze_testnet_encoding() {
577577

578578
#[test]
579579
fn test_asset_freeze_minimal_encoding() {
580-
let tx = TransactionMother::asset_freeze_minimal().build().unwrap();
581-
check_transaction_encoding(&tx, 140);
580+
let tx = TransactionMother::asset_freeze().build().unwrap();
581+
// Just verify it encodes without checking exact size
582+
let encoded = tx.encode().unwrap();
583+
let decoded = Transaction::decode(&encoded).unwrap();
584+
assert_eq!(decoded, tx);
582585
}
583586

584587
#[test]
585588
fn test_asset_freeze_with_group_encoding() {
586-
let tx = TransactionMother::asset_freeze_with_group()
587-
.build()
588-
.unwrap();
589+
let tx = TransactionMother::asset_freeze().build().unwrap();
589590

590591
// Verify group field is set
591592
if let Transaction::AssetFreeze(fields) = &tx {
@@ -601,16 +602,16 @@ fn test_asset_freeze_with_group_encoding() {
601602
#[test]
602603
fn test_asset_freeze_real_transaction_ids() {
603604
// Test with mainnet freeze
604-
let freeze_tx = TransactionMother::asset_freeze_mainnet().build().unwrap();
605+
let freeze_tx = TransactionMother::asset_freeze().build().unwrap();
605606
let freeze_id = freeze_tx.id().unwrap();
606607
assert_eq!(freeze_id.len(), 52); // Base32 encoded length
607608

608609
// Test with mainnet unfreeze
609-
let unfreeze_tx = TransactionMother::asset_unfreeze_mainnet().build().unwrap();
610+
let unfreeze_tx = TransactionMother::asset_unfreeze().build().unwrap();
610611
let unfreeze_id = unfreeze_tx.id().unwrap();
611612
assert_eq!(unfreeze_id.len(), 52);
612613

613-
// Verify freeze and unfreeze have different IDs (different first_valid)
614+
// Verify freeze and unfreeze have different IDs (different frozen value)
614615
assert_ne!(freeze_id, unfreeze_id);
615616
}
616617

crates/algokit_transact/src/transactions/asset_freeze.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use crate::address::Address;
77
use crate::transactions::common::TransactionHeader;
8-
use crate::utils::{is_zero, is_zero_addr};
8+
use crate::utils::{is_false_opt, is_zero, is_zero_addr};
99
use crate::Transaction;
1010
use derive_builder::Builder;
1111
use serde::{Deserialize, Serialize};
@@ -46,7 +46,8 @@ pub struct AssetFreezeTransactionFields {
4646
/// `false` to unfreeze the asset holdings (allow transfers).
4747
#[serde(rename = "afrz")]
4848
#[serde(default)]
49-
pub frozen: bool,
49+
#[serde(skip_serializing_if = "is_false_opt")]
50+
pub frozen: Option<bool>,
5051
}
5152

5253
impl AssetFreezeTransactionBuilder {

crates/algokit_transact_ffi/src/transactions/asset_freeze.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl From<algokit_transact::AssetFreezeTransactionFields> for AssetFreezeTransac
2424
Self {
2525
asset_id: tx.asset_id,
2626
freeze_target: tx.freeze_target.into(),
27-
frozen: tx.frozen,
27+
frozen: tx.frozen.unwrap_or(false),
2828
}
2929
}
3030
}
@@ -46,7 +46,7 @@ impl TryFrom<Transaction> for algokit_transact::AssetFreezeTransactionFields {
4646
header,
4747
asset_id: data.asset_id,
4848
freeze_target: data.freeze_target.try_into()?,
49-
frozen: data.frozen,
49+
frozen: Some(data.frozen),
5050
})
5151
}
5252
}

0 commit comments

Comments
 (0)