Sender
Overview
Within the context of a transaction that comprises seven distinct generics, From
represents the second generic field — the entity that initiates the transaction. It is required in three environments: the integration test, the parametric test, and the interactor.
A transaction originating from a contract environment cannot have a sender in the contract environment. The reason is that the current contract is always the same: the contract that starts the transaction.
Diagram
The sender is being set using the .from(...)
method. Several types can be specified:
No sender
Transactions initiated in the contract environment have no sender specified. There is no need for sender identification because it always refers to the executing contract itself.
#[payable("EGLD")]
#[endpoint]
fn transfer_egld(&self, to: ManagedAddress, amount: BigUint) {
self.tx().to(&to).egld(&amount).transfer();
}
Explicit sender
For transactions launched in any other environment than the contract one, it is required to specify the sender. Meaning that, in most cases, no tx can be created without defining the sender.
In the following section, we will outline the various types of entities that can be designated as the sender in a transaction.
ManagedAddress
The function below is a snippet from an interactor whose purpose is to deploy a contract. The .from
call, which sets the sender, is the main focus of this example. The sender is a hardcoded ManagedAddress, which illustrates a wallet.
async fn deploy(&mut self) {
let wallet: ManagedAddress<StaticApi> = ManagedAddress::new_from_bytes(&[7u8; 32]);
self.interactor
.tx()
.from(wallet)
.typed(proxy::Proxy)
.init(0u32)
.code(&self.code)
.gas(NumExpr("70,000,000"))
.returns(ReturnsNewBech32Address)
}
Address
The example beneath is a fragment for a blackbox test that runs the add function from a proxy. The sender is received as a parameter in this function.
fn add_one(&mut self, from: &AddressValue) {
self.world
.tx()
.from(from)
.to(self.receiver)
.typed(proxy::Proxy)
.add(1u32)
.run();
}
For parametric testing, there is particular address type name:
- TestAddress
- encodes a dummy address, equivalent to
"address:{}"
; for the example below it is equivalent to"address:owner"
; - contains two functions:
.eval_to_array()
parse the address into an array of u8.eval_to_expr()
return the address as a String object
- encodes a dummy address, equivalent to
const OWNER_ADDRESS: TestAddress = TestAddress::new("owner");
fn add_one(&mut self) {
self.world
.tx()
.from(OWNER_ADDRESS)
.to(self.receiver)
.typed(proxy::Proxy)
.add(1u32)
.run();
}
Bech32Address
In order to avoid repeated conversions, it keeps the bech32 representation inside. It wraps the address and presents it as a bech32 expression.
fn add_one(&mut self, wallet_address: Bech32Address) {
self.world
.tx()
.from(wallet_address)
.to(self.receiver)
.typed(proxy::Proxy)
.add(1u32)
.run();
}
Automatic wallet selection in interactors
Wallets are registered beforehand when it comes to interactor operations. An automated signature is applied to the transaction. More details about interactors here.