Skip to main content

thruput_testkit/
caller.rs

1//! A cloneable handle for submitting transactions from an agent's account.
2//!
3//! [`AgentContext`](crate::AgentContext) holds the parts of an agent that must
4//! stay exclusive (its mailbox and random stream). [`Caller`] is the part that
5//! need not: the agent's account and the network it submits to. Clone one out
6//! with [`AgentContext::caller`](crate::AgentContext::caller) to hold it in a
7//! typed contract client, store it in a struct, or move it into a spawned task.
8
9use thruput_json_rpc_types::responses::TransactionReceipt;
10use thruput_xdr::contract::ContractEntrypointID;
11use thruput_xdr::types::ContractAddress;
12
13use crate::account::Account;
14use crate::error::Result;
15use crate::network::{Network, SubmittedTransaction};
16
17/// An agent's account bound to the network it submits to.
18///
19/// Clones share the account's nonce sequence, so transactions submitted
20/// through any clone never collide. Nonces (and so the addresses of deployed
21/// contracts) are assigned in submission order: submissions made one after
22/// another are deterministic for a given seed, while submissions raced from
23/// concurrent tasks are numbered in whatever order the tasks reach them.
24#[derive(Debug, Clone)]
25pub struct Caller {
26    pub(crate) account: Account,
27    pub(crate) network: Network,
28}
29
30impl Caller {
31    pub(crate) fn new(account: Account, network: Network) -> Self {
32        Self { account, network }
33    }
34
35    /// The on-chain wallet address transactions are submitted from.
36    pub fn address(&self) -> ContractAddress {
37        self.account.address()
38    }
39
40    /// Handle to the network transactions are submitted to.
41    pub fn network(&self) -> &Network {
42        &self.network
43    }
44
45    /// Call a deployed contract method from this account, awaiting the
46    /// receipt. The receipt is returned even when execution reverted.
47    pub async fn call(
48        &self,
49        target: ContractAddress,
50        entrypoint: ContractEntrypointID,
51        calldata: &[u8],
52    ) -> Result<TransactionReceipt> {
53        self.submit_call(target, entrypoint, calldata)
54            .await?
55            .await_receipt()
56            .await
57    }
58
59    /// Submit a contract call without waiting for its receipt.
60    pub async fn submit_call(
61        &self,
62        target: ContractAddress,
63        entrypoint: ContractEntrypointID,
64        calldata: &[u8],
65    ) -> Result<SubmittedTransaction> {
66        self.account
67            .submit_call(&self.network, target, entrypoint, calldata)
68            .await
69    }
70}
71
72impl AsRef<Caller> for Caller {
73    fn as_ref(&self) -> &Caller {
74        self
75    }
76}