Wallets API

Who can use this feature

  • Org accounts on any plan
  • User accounts with at least Admin org-level role to create wallets

Wallet is the top-level object that represents a wallet, and it contains all the other objects that are related to a wallet. For now, a Wallet exists on a singular Network, even if there are multiple Wallets with the same blockchain address on different Networks.

Create Wallet

There are multiple ways to create a Levain Wallet programmatically:

  1. via Levain SDK (recommended)
  2. via Levain GraphQL API (advanced)

Programmatically via Levain SDK

We recommend using the Levain SDK to create your keys and wallets. The SDK will handle the key generation, key encryption, wallet creation and activation steps for you.

SDKTypeScript
import { LevainGraphClient, WalletType } from '@levain/wallet-sdk';

const client = new LevainGraphClient({
  // Get your personal access token from https://app.levain.tech/account/tokens
  accessToken: '<Your access token>',
});

// Remember to save the keys somewhere secure!
const { wallet, keys } = await client.createKeysAndWallet({
  orgId,
  name: 'My SDK-created multisig wallet',

  // Select the network you want to create your wallet on.
  // For a list of supported networks, refer to
  // https://developer.levain.tech/products/graph/docs/levain-fundamentals/supported-chains#list-of-supported-blockchain-networks
  // This example points to Ethereum Sepolia
  network: 'caip2:eip155:11155111',

  // This password will be used to encrypt your wallet's private keys.
  // You will need this password to sign transactions from your wallet later on.
  walletPassword: 'SuperSecureWalletPassword',
});

Congratulations! You have successfully created a wallet via the Levain SDK.


Programmatically via Levain GraphQL API

The following section is for users who are comfortable working directly with the Levain GraphQL APIs for creating keys and wallets for more advanced use cases.

We have an accompanying repository of example code for you to refer to. In this example, we will explain to you the portions of the code that are relevant to creating a wallet, and we recommend you to read this with the example code found on our GitHub.

To understand more about the keys used in Levain, refer to Levain Wallet's Security Model and Provable Secure Custody.

Keys are signatories of a Wallet, providing signing capabilities required as part of making transactions from your Levain Wallet. Signing comes in the form of a cryptographic signature, which is generated using the Key's private key.

1. Create Main and Backup Keys

To create a key pair, you can use any tool that supports the secp256k1 curve. For example, you can use Ethers.js to generate a key pair:

EthersTypeScript
import { Wallet } from 'ethers';
import { encrypt } from '@soufflejs/crypto';

// Create and encrypt `Main` key
const mainKeyPair = Wallet.createRandom();
const mainPrivateKeyEncrypted = await encrypt(password, mainKeyPair.privateKey);

// Create `Backup` key
const backupKeyPair = Wallet.createRandom();

When creating your Keys and Wallets programmatically, you are expected to manage your backup procedures as we will not be able to generate a Wallet Recovery Kit for you.

2. Registering Keys with Levain

With the newly generated key pairs (held by you), you can now register these Keys in Levain, without having to share the underlying private keys with us.

To do so, you should use the following GraphQL mutation with the CreateKeyInput input, for every key pair generated by you on your computer locally.

MutationGraphQL
mutation CreateKey($input: CreateKeyInput!) {
  createKey(input: $input) {
    keyId
  }
}
VariablesJSON
{
  "variables": {
    "input": {
      "orgId": "868202983161",
      "name": "My Main Key",
      "type": "ScalarNeutered",
      "publicKey": "0x04bd...06f0",
      "retrieveIfExists": true
    }
  }
}
ResponseJSON
{
  "data": {
    "createKey": {
      "keyId": "01234abc-e382-4d2f-bcea-0b789c00c18b"
    }
  }
}

Replace the publicKey value with the mainKeyPair.publicKey and backupKeyPair.publicKey created in Create Main and Backup Keys for the respective key creation.

3. Creating a Wallet

To create a Wallet on a network, you can use the following GraphQL mutation with the CreateWalletInput input.

MutationGraphQL
mutation CreateWallet($input: CreateWalletInput!) {
  createWallet(input: $input) {
    walletId
    organizationNetwork {
      network {
        protocolName
        networkName
      }
    }
    name
    status
    mainAddress
  }
}
VariablesJSON
{
  "variables": {
    "input": {
      "orgId": "868202983161",
      "type": "EvmContractSimpleMultiSig",
      "network": "caip2:eip155:11155111",
      "name": "API-created Levain Wallet Sepolia",
      "description": "API-created Levain Wallet powered by SimpleMultiSig",
      "mainKey": {
        "keyId": "01234abc-e382-4d2f-bcea-0b789c00c18b",
        "passwordRecoveryKeyId": "01234abc-e382-4d2f-bcea-0b789c00c18b",
        "encryptedPrivateKey": "..."
      },
      "backupKey": {
        "keyId": "01234abc-e382-4d2f-bcea-0b789c00c18b"
      }
    }
  }
}
ResponseJSON
{
  "data": {
    "createWallet": {
      "walletId": "6da5fb38-a286-4656-a842-9b94a51065bf",
      "organizationNetwork": {
        "network": {
          "protocolName": "Ethereum",
          "networkName": "Sepolia Testnet"
        }
      },
      "name": "API-created Levain Wallet Sepolia",
      "status": "ACTIVE",
      "mainAddress": "0x734251c89a207d743f483fdfc56c15a8637524f2"
    }
  }
}

4. Activating the Wallet

Creating a wallet is an asynchronous process, as it entails deploying a smart contract on the blockchain. Every newly created Wallet will have a status of INACTIVE until it is activated.

To do so, you can use the following GraphQL mutation:

MutationGraphQL
mutation ActivateWallet($input: ActivateWalletInput!) {
  activateWallet(input: $input) {
    walletId
    status
  }
}
VariablesJSON
{
  "variables": {
    "input": {
      "walletId": "6da5fb38-a286-4656-a842-9b94a51065bf"
    }
  }
}
ResponseJSON
{
  "data": {
    "activateWallet": {
      "walletId": "6da5fb38-a286-4656-a842-9b94a51065bf",
      "status": "ACTIVE"
    }
  }
}

When the wallet contract deployment has sufficient confirmations, the Wallet will be activated and its status will be updated to ACTIVE, indicating that it is now ready for use.

And that is it! You have now created a Wallet on Levain.


Retrieve

There are multiple ways to retrieve wallet details. The first is to use the wallet query. It only requires the walletId as an input and returns the Wallet object.

QueryGraphQL
query Wallet($walletId: ID!) {
  wallet(walletId: $walletId) {
    walletId
    organizationNetworkId
    organizationNetwork {
      network {
        protocolName
        networkName
      }
    }
    name
    status
    mainAddress
  }
}
VariablesJSON
{
  "variables": {
    "walletId": "01234abc-e382-4d2f-bcea-0b789c00c18b"
  }
}
ResponseJSON
{
  "data": {
    "createWallet": {
      "walletId": "01234abc-e382-4d2f-bcea-0b789c00c18b",
      "organizationNetwork": {
        "network": {
          "protocolName": "Ethereum",
          "networkName": "Goerli Testnet"
        }
      },
      "name": "API-created Levain Wallet 1",
      "status": "ACTIVE",
      "mainAddress": "0x734251c89a207d743f483fdfc56c15a8637524f2"
    }
  }
}

Update

You can update wallets using the following GraphQL mutation with the UpdateWalletInput input, though only wallet name and description can be updated.

You cannot change the wallet type or the network it is on, and you cannot change the main address due to the immutable nature of the blockchain. At this point, you also cannot change the main or backup keys.

MutationGraphQL
mutation UpdateWallet($input: UpdateWalletInput!) {
  updateWallet(input: $input)
}
VariablesJSON
{
  "variables": {
    "input": {
      "walletId": "01234abc-e382-4d2f-bcea-0b789c00c18b",
      "name": "My Wallet",
      "description": "My Wallet Description"
    }
  }
}
ResponseJSON
{
  "data": {
    "updateWallet": true
  }
}

Delete

Wallets can never be deleted, they should only be deactivated. At this point, Levain does not support deactivating wallets. If you need to deactivate a wallet, please contact your account manager or email the Levain Product Team.