MainNet Restrictions - Building Custodial Wallet and Services

Hey everyone, we are building a NFT Martketplace (similar to NBA Top Shot - of course) and went pretty far in setting the architecture on the Test Net.
The flow goes like this:

  1. User signs up with email on our website
  2. Our Flow service account creates another flow account for the newly registered user (we eat all the transaction fees) and we store the private key for the new user somewhere (custodial wallet concept)
  3. The user will be able to purchase tokens from the platform or from other users for $$$ or other crypto currencies (happens via Coinbase or Stripe or Braintree) and we will transfer the NFTs after the purchase has been successful (again, we eat all the transaction fees)
    This concept means that we (the marketplace platform) will own the rights to manage user accounts. We donā€™t want users to transfer their NFTs outside the platform, of course. Exactly what Dapper is doing on the NBA Top Shot - you see your flow account address but canā€™t manage it because they are in control of the keys.

This all works on the Test Net (weā€™ve build and tested it through and through) but something Iā€™ve read on the Forum the other day got me concerned:

@flowjosh said:

Currently, if you want to have an account on mainnet, you need to use Blocto, ledger, or one of the other custodial exchanges. In the future, youā€™ll definitely be possible to just use the CLI or sdk to manage an account with your own private keys and such on your own, but that isnā€™t possible yet because account creation is restricted to approved accounts.

Does this mean that we (the marketplace) will have to store the keys for newly created users in a Blocto or Ledger wallet? If yes, are there any guidelines on how to do that?

1 Like

If you create your own wallet service, then you can get permission to create accounts for your users. My answer from earlier was referring to just a regular user wanting to create a Flow account. If you build a wallet service, youā€™ll be able to manage everything all yourself, but youā€™ll need to get in contact with the Flow team first in order to get permission to create accounts on mainnet.
Does that make sense?

Tnx @flowjosh That makes a lot of sense. We started building on the Test Net to get as close as possible to the ā€œrealā€ deal. The difference is: real money/cost for processing transactions + building a more secure architecture and getting the approval from the Flow Team (as per your guidelines).
Could you recommend any best practices or third party services we could use for the Wallet Service part? We donā€™t want to start implementing something that could potentially be rejected by the Flow teamā€¦ I hope that makes sense :slight_smile:

We wonā€™t reject anything unless it is doing something obviously malicious or irresponsible. Unfortunately, if you donā€™t want to build your own, your only option for a wallet service at this point is Blocto. There are other teams who are working on wallets, but none of them are ready yet, so we canā€™t talk about them at this point.

Ok, that is great. Thank you for the details.

Hi @dh77 , Thanks for initiating this conversation as this cleared many of my doubts.
I am also developing the same use case as yours but Iā€™m not sure how to create our own wallet service. We donā€™t wanna use Blocto. We also want to create an NFT marketplace and buy or sell NFTs on it with flow coins. We need our own wallet for storing the flow coins and the NFTs a user possess.
Can you please guide me on this? Please help me out.

Thanks in advance.

Hey @Kartik - always happy to help.
I think the name ā€œwalletā€ is a bit misleading in the context of blockchain - you should think of it more as a credit card holder than a real world wallet because virtual wallets donā€™t hold any value, their purpose is to enable access to your assets on the blockchain - just like a credit card gives you access to your bank account. Basically, both the fungible and non-fungible tokens are stored inside the storage within the accounts on blockchain and that is where the value is - the virtual wallets are simply a storage for your private keys which give you access to those coins in the blockchain.
If you want to build the Wallet Service (or Wallet hosting) by yourself, you must be aware of the security risks. We will initially try to use a secure third party for this and then later on maybe build our own.
Hope this helpedā€¦

1 Like

Hi @dh77, thank you so much for the help. This really helped me a lot to understand Flow better. :slight_smile:
So according to me, now the flow goes like this :

We generate keys and account on the testnet ā†’ store these keys to some safe location ā†’ user uses these keys to access his assets i.e. his stored flow coins and do some transactions.

am I correct ? Please correct me if Iā€™m wrong. Also, if you can provide some link or docs to login into testnet, it would be of great help as Iā€™m new to flow and Iā€™m not able to login into testnet. It throws errors all over.

Thanks,
Kartik

Yes @Kartik that is correct.
When it comes to the Test Net - first you need to create an account here https://testnet-faucet-v2.onflow.org/
Instructions here: https://docs.onflow.org/dapp-deployment/testnet-deployment/ (you need to have Flow CLI installed locally to generate keys).
Hope this helps

1 Like

Hi @dh77 , Your replies are really helping me a lot :slight_smile: . I am now able to mint an NFT and fetch its metadata on the testnet. I have flow coins in my created account but Iā€™m not sure how to transfer them from account to another on the testnet. Also, how can we charge transaction fees with each transaction? Please guide me. Thanks in advance ! :slight_smile:

1 Like

Hey @Kartik - always happy to help. This is where they explain how to transfer coins from one account to another ā†’ Transfer FLOW - Flow Documentation
One of the accounts will always have to pay the transaction fee which means that this account needs to have a legit flow token balance. A bit more about the transaction fees: Key Concepts - Flow Documentation

2 Likes

Hey @dh77 , Thanks for this but do we have the same documentation to Transfer Flow by using Flow Js SDK ?
I can see the documentation provided is for Go SDK. Do you have anything on this ? i.e. using JS SDK. Thanks in advance man ! :slight_smile:

Hey @Kartik - I canā€™t help you there unfortunately. We are using the GO SDK - and the only reason is because the access routes for the testnet were not working in JS SDK - but there is a workaround. Who knows, maybe we will switch back to JS after a whileā€¦

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

Thank you so much @qvvg and @dh77 for helping me throughout. :slight_smile:

I was thinking that Blocto provides access to Flow testnet and Iā€™m using the ā€˜AuthClusterā€™ code for signing in a user. However, I donā€™t want Blocto to generate keys for user and creating his account address. I want to the login flow like this :

User comes for the first time ā†’ tries to signUp ā†’ My Application will generate keys and his account address, will store the keys to some safe location ā†’ User Logs in .

The problem is how will I connect to the Flow Testnet/Mainnet without using Blocto by using the address stored locally? When I use ā€˜https://fcl-discovery.onflow.org/testnet/authnā€™ , it provides Blocto as the provider option and the user signs in using a mail address. If the user does not exists, it registers the user by itself and provides an address to login. How can I skip this and provide my own registration and login process to Flow?

And also, in the .env file, we have REACT_APP_CONTRACT_PROFILE , this is going to be my companyā€™s account, isnā€™t it ? which will pay for the initial transaction charges for registering a user and on which the contracts are deployed. Am I right in this regard?

Thanks !