Icon HelpCircleForumIcon Link

⌘K

Icon HelpCircleForumIcon Link
Locking and Unlocking

Icon LinkLocking and Unlocking

The kinds of operations we can perform with a Wallet Icon Link instance depend on whether or not we have access to the wallet's private key.

In order to differentiate between Wallet Icon Link instances that know their private key and those that do not, we use the WalletUnlocked Icon Link and WalletLocked Icon Link types respectively.

Icon LinkWallet States

The WalletUnlocked Icon Link type represents a wallet whose private key is known and stored internally in memory. A wallet must be of type WalletUnlocked Icon Link in order to perform operations that involve signing messages or transactions .

The WalletLocked Icon Link type represents a wallet whose private key is not known or stored in memory. Instead, WalletLocked Icon Link only knows its public address. A WalletLocked Icon Link cannot be used to sign transactions, however it may still perform a whole suite of useful operations including listing transactions, assets, querying balances, and so on.

Note that the WalletUnlocked Icon Link type implements most methods available on the WalletLocked Icon Link type. In other words, WalletUnlocked Icon Link can be thought of as a thin wrapper around WalletLocked Icon Link that provides greater access via its private key.

Icon LinkBasic Example

import type { WalletLocked, WalletUnlocked } from 'fuels';
import { Provider, Wallet } from 'fuels';
 
import { LOCAL_NETWORK_URL } from '../../../env';
 
// We can use the `generate` to create a new unlocked wallet.
const provider = await Provider.create(LOCAL_NETWORK_URL);
const myWallet: WalletUnlocked = Wallet.generate({ provider });
 
// or use an Address to create a wallet
const someWallet: WalletLocked = Wallet.fromAddress(myWallet.address, provider);

Icon LinkOptional Provider

You can choose not to pass through a provider argument on Wallet construction:

import type { WalletUnlocked } from 'fuels';
import { Wallet } from 'fuels';
 
// You can create a wallet, without a provider
let unlockedWalletWithoutProvider: WalletUnlocked = Wallet.generate();
unlockedWalletWithoutProvider = Wallet.fromPrivateKey(
  unlockedWalletWithoutProvider.privateKey
);
 
// All non-provider dependent methods are available
unlockedWalletWithoutProvider.lock();
 
// All provider dependent methods will throw
try {
  await unlockedWalletWithoutProvider.getCoins();
} catch (e) {
  console.log('error', e);
}

Icon LinkTransitioning States

A WalletLocked Icon Link instance can be unlocked by providing the private key:

import type { WalletLocked, WalletUnlocked } from 'fuels';
import { Provider, Wallet } from 'fuels';
 
import { LOCAL_NETWORK_URL } from '../../../env';
 
const provider = await Provider.create(LOCAL_NETWORK_URL);
const wallet: WalletUnlocked = Wallet.generate({ provider });
const PRIVATE_KEY = wallet.privateKey;
 
// Lock an existing wallet
const lockedWallet: WalletLocked = Wallet.fromAddress(wallet.address, provider);
 
// Unlock an existing wallet
const someUnlockedWallet: WalletUnlocked = lockedWallet.unlock(PRIVATE_KEY);

A WalletUnlocked Icon Link instance can be locked using the lock method:

import type { WalletUnlocked } from 'fuels';
import { Provider, Wallet } from 'fuels';
 
import { LOCAL_NETWORK_URL } from '../../../env';
 
const provider = await Provider.create(LOCAL_NETWORK_URL);
 
const unlockedWallet: WalletUnlocked = Wallet.generate({ provider });
const newlyLockedWallet = unlockedWallet.lock();

Most wallet constructors that create or generate a new wallet are provided on the WalletUnlocked Icon Link type. Consider locking the wallet with the lock method after the new private key has been handled in order to reduce the scope in which the wallet's private key is stored in memory.

Icon LinkDesign Guidelines

When designing APIs that accept a wallet as an input, we should think carefully about the kind of access that we require. API developers should aim to minimise their usage of WalletUnlocked Icon Link in order to ensure private keys are stored in memory no longer than necessary to reduce the surface area for attacks and vulnerabilities in downstream libraries and applications.

Icon LinkFull Example

For a full example of how to lock and unlock a wallet, see the snippet below:

import type { WalletLocked, WalletUnlocked } from 'fuels';
import { Provider, Wallet } from 'fuels';
 
import { LOCAL_NETWORK_URL } from '../../../env';
 
// We can use the `generate` to create a new unlocked wallet.
const provider = await Provider.create(LOCAL_NETWORK_URL);
const myWallet: WalletUnlocked = Wallet.generate({ provider });
 
// or use an Address to create a wallet
const someWallet: WalletLocked = Wallet.fromAddress(myWallet.address, provider);
 
const wallet: WalletUnlocked = Wallet.generate({ provider });
const PRIVATE_KEY = wallet.privateKey;
 
// Lock an existing wallet
const lockedWallet: WalletLocked = Wallet.fromAddress(
  myWallet.address,
  provider
);
 
// Unlock an existing wallet
const someUnlockedWallet: WalletUnlocked = lockedWallet.unlock(PRIVATE_KEY);
 
const unlockedWallet: WalletUnlocked = Wallet.generate({ provider });
const newlyLockedWallet = unlockedWallet.lock();
 
// You can create a wallet, without a provider
let unlockedWalletWithoutProvider: WalletUnlocked = Wallet.generate();
unlockedWalletWithoutProvider = Wallet.fromPrivateKey(
  unlockedWalletWithoutProvider.privateKey
);
 
// All non-provider dependent methods are available
unlockedWalletWithoutProvider.lock();
 
// All provider dependent methods will throw
await expect(() => unlockedWalletWithoutProvider.getCoins()).rejects.toThrow(
  /Provider not set/
);