MainNet Restrictions - Building Custodial Wallet and Services

To transfer flow, it is a transaction like any other transaction.

If we are talking about the FLOW fungible token on testnet and we wanted to send Flow from one account to another account the cadence for the transaction would look like this.

import FungibleToken from 0x7e60df042a9c0868

transaction(amount: UFix64, to: Address) {
  let vault: @FungibleToken.Vault
  
  prepare(currentUser: AuthAccount) {
    self.vault <- currentUser
      .borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
      .withdraw(amount: amount)
  }

  execute {
    getAccount(to)
      .getCapability(/public/flowTokenReceiver)!
      .borrow<&{FungibleToken.Receiver}>()!
      .deposit(from: <- self.vault)
  }
}

Version 0.0.73 of FCL will make fcl.mutate available (can access it now by using @onflow/fcl@0.0.73-alpha.3). Mutate lets you submit the above cadence transaction code to the chain, defaulting authorization by the current user (if you are doing this from a node server where the “currentUser” is an account you control there is an additional step, which can be found here: flow-js-sdk/mutate.md at master · onflow/flow-js-sdk · GitHub).

We can submit the above cadence transaction code to Flow with:

import {mutate, tx} from "@onflow/fcl"

const CODE = `
import FungibleToken from 0x7e60df042a9c0868

transaction(amount: UFix64, to: Address) {
  let vault: @FungibleToken.Vault
  
  prepare(currentUser: AuthAccount) {
    self.vault <- currentUser
      .borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
      .withdraw(amount: amount)
  }

  execute {
    getAccount(to)
      .getCapability(/public/flowTokenReceiver)!
      .borrow<&{FungibleToken.Receiver}>()!
      .deposit(from: <- self.vault)
  }
}
`

// send 10.0 FLOW to my Flow Account
var txId = await mutate({
  cadence: CODE,
  args: (arg, t) => [
    arg("10.0", t.UFix64),               // amount
    arg("0xba1132bc08f82fe2", t.Address) // to
  ],
  limit: 55,
})

// know when the transaction was successful and permanent
var txStatus = await tx(txId).onceSealed()

The above code if you were to run it as is would send me 10.0 Flow from your Flow account.

In versions before 0.0.73 (and 0.0.73 can still do it this way too) it is a bit more verbose. Assuming CODE is the same value.

import * as fcl from "@onflow/fcl"

var txId = await fcl.send([
  fcl.transaction(CODE),
  fcl.limit(55),
  fcl.proposer(fcl.currentUser().authorization),
  fcl.payer(fcl.currentUser().authorization),
  fcl.authorizations([
    fcl.currentUser().authorization,
  ]),
  fcl.args([
    fcl.arg("10.0", fcl.t.UFix64),
    fcl.arg("0xba1132bc08f82fe2", fcl.t.Address)
  ])
]).then(fcl.decode)

var txStatus = await fcl.tx(txId).onceSealed()

When you are running these transactions from node, you are responsible for the authorization function as you wont have access to fcl.currentUser().authorization, you can learn about custom authorization functions here: flow-js-sdk/authorization-function.md at master · onflow/flow-js-sdk · GitHub

For the above example using fcl.send(...).then(fcl.decode) everywhere you see fcl.currentUser().authorization you would replace with your own authorization function.

For fcl.mutate (the first example) you would pass it in as authz.

import {mutate, tx} from "@onflow/fcl"
import {myCustomAuthzFn} from "./my-custom-authorization-function"

var txId = await mutate({
  cadence: CODE,
  args: (arg, t) => [
    arg("10.0", t.UFix64),
    arg("0xba1132bc08f82fe2", t.Address)
  ],
  limit: 55,
  authz: myCustomAuthzFn, // pass it in like this
})
1 Like