iota_cluster_test/test_case/
native_transfer_test.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use async_trait::async_trait;
6use iota_json_rpc_types::IotaTransactionBlockResponse;
7use iota_types::{
8    base_types::{IotaAddress, ObjectID},
9    crypto::{AccountKeyPair, get_key_pair},
10    object::Owner,
11};
12use jsonrpsee::rpc_params;
13use tracing::info;
14
15use crate::{
16    TestCaseImpl, TestContext,
17    helper::{BalanceChangeChecker, ObjectChecker},
18};
19
20pub struct NativeTransferTest;
21
22#[async_trait]
23impl TestCaseImpl for NativeTransferTest {
24    fn name(&self) -> &'static str {
25        "NativeTransfer"
26    }
27
28    fn description(&self) -> &'static str {
29        "Test tranferring IOTA coins natively"
30    }
31
32    async fn run(&self, ctx: &mut TestContext) -> Result<(), anyhow::Error> {
33        info!("Testing gas coin transfer");
34        let mut iota_objs = ctx.get_iota_from_faucet(Some(1)).await;
35        let gas_obj = ctx.get_iota_from_faucet(Some(1)).await.swap_remove(0);
36
37        let signer = ctx.get_wallet_address();
38        let (recipient_addr, _): (_, AccountKeyPair) = get_key_pair();
39        // Test transfer object
40        let obj_to_transfer: ObjectID = *iota_objs.swap_remove(0).id();
41        let params = rpc_params![
42            signer,
43            obj_to_transfer,
44            Some(*gas_obj.id()),
45            (2_000_000).to_string(),
46            recipient_addr
47        ];
48        let data = ctx
49            .build_transaction_remotely("unsafe_transferObject", params)
50            .await?;
51        let mut response = ctx.sign_and_execute(data, "coin transfer").await;
52
53        Self::examine_response(ctx, &mut response, signer, recipient_addr, obj_to_transfer).await;
54
55        let mut iota_objs_2 = ctx.get_iota_from_faucet(Some(1)).await;
56        // Test transfer iota
57        let obj_to_transfer_2 = *iota_objs_2.swap_remove(0).id();
58        let params = rpc_params![
59            signer,
60            obj_to_transfer_2,
61            (2_000_000).to_string(),
62            recipient_addr,
63            None::<u64>
64        ];
65        let data = ctx
66            .build_transaction_remotely("unsafe_transferIota", params)
67            .await?;
68        let mut response = ctx.sign_and_execute(data, "coin transfer").await;
69
70        Self::examine_response(ctx, &mut response, signer, recipient_addr, obj_to_transfer).await;
71        Ok(())
72    }
73}
74
75impl NativeTransferTest {
76    async fn examine_response(
77        ctx: &TestContext,
78        response: &mut IotaTransactionBlockResponse,
79        signer: IotaAddress,
80        recipient: IotaAddress,
81        obj_to_transfer_id: ObjectID,
82    ) {
83        let balance_changes = &mut response.balance_changes.as_mut().unwrap();
84        // for transfer we only expect 2 balance changes, one for sender and one for
85        // recipient.
86        assert_eq!(
87            balance_changes.len(),
88            2,
89            "Expect 2 balance changes emitted, but got {}",
90            balance_changes.len()
91        );
92        // Order of balance change is not fixed so need to check who's balance come
93        // first. this make sure recipient always come first
94        if balance_changes[0].owner.get_owner_address().unwrap() == signer {
95            balance_changes.reverse()
96        }
97        BalanceChangeChecker::new()
98            .owner(Owner::AddressOwner(recipient))
99            .coin_type("0x2::iota::IOTA")
100            .check(&balance_changes.remove(0));
101        BalanceChangeChecker::new()
102            .owner(Owner::AddressOwner(signer))
103            .coin_type("0x2::iota::IOTA")
104            .check(&balance_changes.remove(0));
105        // Verify fullnode observes the txn
106        ctx.let_fullnode_sync(vec![response.digest], 5).await;
107
108        let _ = ObjectChecker::new(obj_to_transfer_id)
109            .owner(Owner::AddressOwner(recipient))
110            .check(ctx.get_fullnode_client())
111            .await;
112    }
113}