Transactions
Transactions let you send Cadence code to the Flow blockchain that permanently alters its state.
We are assuming you have read the Scripts Documentation before this, as transactions are sort of scripts with more required things.
While query
is used for sending scripts to the chain, mutate
is used for building and sending transactions. Just like scripts, fcl.mutate
is a JavaScript Tagged Template Literal that we can pass Cadence code into.
Unlike scripts, they require a little more information, things like a proposer, authorizations and a payer, which may be a little confusing and overwhelming.
Sending your first Transaction
There is a lot to unpack in the following code snippet.
It sends a transaction to the Flow blockchain. For the transaction, the current user is authorizing it as both the proposer
and the payer
.
Something that is unique to Flow is the one paying for the transaction doesn't always need to be the one performing the transaction.
Proposers and Payers are special kinds of authorizations that are always required for a transaction.
The proposer
acts similar to the nonce
in Ethereum transactions, and helps prevent repeat attacks.
The payer
is who will be paying for the transaction.
If these are not set, FCL defaults to using the current user for all roles.
fcl.mutate
will return a transactionId
. We can pass the response directly to fcl.tx
and then use the onceSealed
method which resolves a promise when the transaction is sealed.
_17import * as fcl from "@onflow/fcl"_17_17const transactionId = await fcl.mutate({_17 cadence: `_17 transaction {_17 execute {_17 log("Hello from execute")_17 }_17 }_17 `,_17 proposer: fcl.currentUser,_17 payer: fcl.currentUser,_17 limit: 50_17})_17_17const transaction = await fcl.tx(transactionId).onceSealed()_17console.log(transaction) // The transactions status and events after being sealed
Authorizing a transaction
The below code snippet is the same as the above one, except for one extremely important difference.
Our Cadence code this time has a prepare statement, and we are using the fcl.currentUser
when constructing our transaction.
The prepare
statement's arguments directly map to the order of the authorizations in the authorizations
array.
Four authorizations means four &Account
s as arguments passed to prepare
. In this case though there is only one, and it is the currentUser
.
These authorizations are important as you can only access/modify an accounts storage if you have the said accounts authorization.
_21import * as fcl from "@onflow/fcl"_21_21const transactionId = await fcl.mutate({_21 cadence: `_21 transaction {_21 prepare(acct: &Account) {_21 log("Hello from prepare")_21 }_21 execute {_21 log("Hello from execute")_21 }_21 }_21 `,_21 proposer: fcl.currentUser,_21 payer: fcl.currentUser,_21 authorizations: [fcl.currentUser],_21 limit: 50_21})_21_21const transaction = await fcl.tx(transactionId).onceSealed()_21console.log(transaction) // The transactions status and events after being sealed
To learn more about mutate
, check out the API documentation.