Transactions

Transactions

Execute transactions using useFlowTransaction:

import { useFlowTransaction } from '@doodlesteam/flooks';
 
const transaction = `
  import NonFungibleToken from 0x...
  import Doodles from 0x...
 
  transaction(recipient: Address, nftID: UInt64) {
    let withdrawRef: &Doodles.Collection
    let depositRef: &Doodles.Collection{NonFungibleToken.Receiver}
 
    prepare(signer: AuthAccount) {
      self.withdrawRef = signer.borrow<&Doodles.Collection>(from: Doodles.CollectionStoragePath)
        ?? panic("Account does not store an object at the specified path")
 
      self.depositRef = getAccount(recipient).getCapability(Doodles.CollectionPublicPath)
        .borrow<&Doodles.Collection{NonFungibleToken.CollectionPublic}>()
          ?? panic("Could not borrow a reference to the receiver's collection")
    }
 
    execute {
      let nft <- self.withdrawRef.withdraw(withdrawID: nftID)
      self.depositRef.deposit(token: <-nft)
    }
  }`;
 
function Component {
  const { execute, isIdle, isLoading, isSealed, isError } =
    useFlowTransaction({
      code: transaction,
      args: ['0x...', 1],
      onTransactionSealed(result) {
        console.log('Transaction completed!', result.transactionId);
        for (const event of result.events) {
          console.log(event.type, event.data);
        }
      },
      onTransactionError(result) {
        console.error(result.error);
      },
    });
 
  return (
    <button disabled={!isIdle} onClick={() => execute()}>
      {isIdle && 'Transfer NFT'}
      {isLoading && 'Loading...'}
      {isSealed && 'Sealed!'}
      {isError && 'Error'}
    </button>
  );
}

useFlowTransaction also provides you with automatic parsed and validated arguments, and also subscribes to transaction status.


Doing the same with fcl:

import { useEffect, useState } from "react";
import * as fcl from "@onflow/fcl";
 
const transaction = `
  import NonFungibleToken from 0x...
  import Doodles from 0x...
 
  transaction(recipient: Address, nftID: UInt64) {
    let withdrawRef: &Doodles.Collection
    let depositRef: &Doodles.Collection{NonFungibleToken.Receiver}
 
    prepare(signer: AuthAccount) {
      self.withdrawRef = signer.borrow<&Doodles.Collection>(from: Doodles.CollectionStoragePath)
        ?? panic("Account does not store an object at the specified path")
 
      self.depositRef = getAccount(recipient).getCapability(Doodles.CollectionPublicPath)
        .borrow<&Doodles.Collection{NonFungibleToken.CollectionPublic}>()
          ?? panic("Could not borrow a reference to the receiver's collection")
    }
 
    execute {
      let nft <- self.withdrawRef.withdraw(withdrawID: nftID)
      self.depositRef.deposit(token: <-nft)
    }
  }`;
 
function Component {
  const [txStatus, setTxStatus] = useState();
  const [txUnsubscribe, setTxUnsubscribe] = useState();
 
  const execute = async () => {
    const transactionId = await fcl.mutate({
      cadence: transaction,
      args: (arg, t) => [arg("0x...", t.Address), arg("1", t.UInt64)],
    });
 
    const unsubscribe = fcl.tx(txId).subscribe(setTxStatus);
    setTxUnsubscribe(unsubscribe);
  }
 
  useEffect(() => {
    if (txStatus?.status === 4) {
      console.log('Transaction completed!', txStatus.transactionId);
      for (const event of txStatus.events) {
        console.log(event.type, event.data);
      }
      txUnsubscribe();
    } else if (txStatus?.errorMessage !== '') {
      console.error(result.error);
      txUnsubscribe();
    }
  }, [txStatus]);
 
  return (
    <button disabled={!isIdle} onClick={() => execute()}>
      {!txStatus && 'Transfer NFT'}
      {[1, 2, 3].includes(txStatus?.status) && 'Loading...'}
      {txStatus?.status === 4 && 'Sealed!'}
      {txStatus?.errorMessage !== '' && 'Error'}
    </button>
  );
}