Choosing a Wallet as an Enterprise Team: Programmable Wallets

USDC Web3 Services Programmable Wallets API Developer

Blog_choosing-a-wallet

We walk through Programmable Wallets, a groundbreaking innovation that allows developers to offer powerful Web3 wallets with the UX of a Web2 app.

Choosing a Wallet as an Enterprise Team: Programmable Wallets

Wallets are typically the first piece of technology that users encounter when venturing into the world of Web3. Currently, Web3 is associated with difficult UX and a steep learning curve on how these wallets work.

Wallets are notoriously hard to operate. For example, it’s difficult for a new adopter to understand the concepts of gas fees and signing transactions. Similarly, many users are shocked when they discover that losing their recovery phrase leads to a permanent, irreversible loss of the wallet (unlike how Google or Apple accounts work).

In this overview, we will walk through Programmable Wallets, a groundbreaking innovation from Circle that allows enterprises and developers to offer all the power of a Web3 wallet wrapped in the UX of a delightful Web2 app. We’ll look into the pros and cons of the two types of Programmable Wallets, and learn how to create and manage Programmable Wallets through Circle APIs and on-screen using Circle’s Web3 services platform.

Brief Overview of Web3 Wallets

Since there is no central authority keeping track of user accounts on public blockchains, users need wallets to hold their USDC, digital assets (tokens, NFTs, etc.) and to conduct transactions.

Wallets, at their core, are straightforward—they are just a private key, a public key, and a public address.

The private key is a large hexadecimal number that gives access to the wallet and is used to sign transactions. This private key must be kept secret at all times. If it is compromised, the wallet is compromised. The private key is synonymous with the wallet itself: the one who controls the private key controls the wallet.

The public key is, as the name says, a public piece of information that can be used to prove that a transaction was signed by the owner of the wallet.

The public address is a unique address, derived from the public key, that can be shared with others so that they can send digital assets to the wallet.

image3-2

The majority of wallets today are browser extensions or mobile apps such as MetaMask. These wallets allow users to connect to a Web3 dapp (think of this as logging in) and sign transactions.

The wallets typically have additional functionality such as trading tokens, conducting swaps, and viewing owned NFTs.

For most users, operating a wallet through an extension is cumbersome and an overall poor experience. Requiring users to keep their recovery phrase secure and reminding them to not accidentally sign malicious transactions makes things even harder.

To overcome these challenges, Circle created Programmable Wallets.

Programmable Wallets from Circle

Circle’s Programmable Wallets allow developers to create secure, embedded wallets in their apps—at scale and with a familiar UX.

In other words, it is a wallet as a service that uses familiar Web2 paradigms such as a PIN, security questions, and passwords instead of recovery phrases and browser extensions.

image7-2

Programmable Wallets have a host of advantages for both developers and end-users.

For developers, Programmable Wallets offer:

  1. More functionality with less code: allow developers to create, maintain, and operate wallets, all through familiar REST APIs and mobile SDKs (both Android and iOS). And it’s fast to learn—it assumes no knowledge of Solidity or self-custodial wallet solutions like MetaMask.
  2. Blockchain agnostic: developers are able to deploy their wallets to multiple blockchains at the same time with minimal changes and blockchain knowledge. Adding support for an additional blockchain is as simple as changing a parameter on a REST API call.
  3. Flexible infrastructure options: abstracting away the low-level blockchain details from the end-user allows developers to create frictionless UX on par with its Web2 counterparts such as Google or Apple.
  4. Operations monitoring: with Circle’s Web3 services console, developers can monitor transactions, see an overview of all parties, and get detailed error reports.

For end-users, the advantages are also powerful:

  1. Familiar UX: the wallet experience for end-users is streamlined and simplified. In many cases, users won’t be able to tell that they are using a Web3 wallet at all.
  2. Simple access: recovery phrases and hexadecimal addresses in favor of easier-to-remember PINs and security questions users are already familiar with.
  3. Advanced security: multi-party computation (MPC) technology manages private keys by distributing key shards across multiple parties to ensure wallets are guarded against, unauthorized access and theft of funds/assets.
  4. Gas free: users can conduct transactions without worrying about gas fees (fees can be sponsored by app developers). This eliminates the large hurdle of users acquiring funds to conduct transactions.

User-Controlled vs. Dev-Controlled Wallets

Programmable Wallets come in two varieties: user-controlled and dev-controlled. The “control” here refers to the party that possesses the private key. As mentioned earlier, the party that holds the private keys controls the ownership of the wallet.

With user-controlled wallets, developers give end-users complete control over their wallets and their digital assets. A transaction can only be conducted with explicit authorization from the user. The caveat is that user-controlled wallets require users to have a base-level understanding of how Web3 wallets work. Users will also still need to prove ownership of the wallet through methods such as security questions.

Dev-controlled wallets allow developers to fully control the wallet and its assets. This provides a completely streamlined, tailored experience for the end-user, with all blockchain details (such as gas fees and transactions) abstracted away. The caveat here is that the end-user does not control, or really own, the assets in these wallets.

Choosing a Wallet Type

Both options come with the powerful tools you need to work with and manage the wallets. In both cases, Programmable Wallets offer simple creation and management of the wallets, and provide approachable user flows and smart contract integration. Builders and users of Programmable Wallets can execute transactions, interact with smart contracts, and sign messages.

The choice really comes down to who owns the private key, and thus who controls the execution of transactions and signing of messages. It’s a tradeoff between offering optimal end-user experience or prioritizing end-user autonomy.

With user-controlled wallets, users have a PIN code and a set of security questions for account recovery. This abstracts away the complexity of seed phrases, but users are still responsible for their private keys through their PIN code.

User-controlled wallets offer an improved UX, but prioritize end-user autonomy.

With developer-controlled wallets, you control virtually all the blockchain interactions. Users don’t need to understand the complexities of Web3. You handle everything for them.

Developer-controlled wallets prioritize an optimal UX and are concerned less with end-user autonomy.

As with most other software decisions, the decision depends on the context and the nature of your app: what your app prioritizes, and what is best for your users.

 

Tutorial: Setting Up a Dev-Controlled Wallet

Let’s set up a dev-controlled wallet where the developer controls the private keys of the wallet andis able to conduct transactions on the user’s behalf without needing a signature every time.

Step 1: Create a Web3 Services Account

In order to access Circle’s powerful APIs and SDKs, we first need a Web3 services account. You can do this for free on the Circle website.

image5-2

Once you’ve created an account, log in to the Web3 services console. It should look like this:

image2-1

From the left-menu pane, click on API keys. From here, click Create a Key from the top right. You can name your key anything. Ensure you save this key in a safe place as you’ll have to regenerate a new key if you lose this one.

Step 2: Generate an Entity Secret

In order to operate dev-controlled wallets, we need an entity secret. This secret will be registered with Circle’s Web3 services, and an encrypted version will be used in API calls.

Generating an entity secret takes a little work and entails the generation of a 32-byte hexadecimal key. You can do this from your terminal using the following command:


$ openssl rand -hex 32

You should get a code that looks something like this: 7dd20a036e6edca7906d0c06ddd47db2c8a78f299302070ed711475364da48ec.

Step 3: Get Public Key

Let’s get the public key associated with our account using a Circle API call. This public key will be essential in the generation of the final entity secret ciphertext.


$ curl --request GET \
     --url 'https://api.circle.com/v1/w3s/config/entity/publicKey' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer '

You should get an output that looks something like this:


$ {"data":{"publicKey":"-----BEGIN RSA PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArhXRK6hVYnt+H5vUyz7v\nWMHoh4of7PEX2w+BCtLfbqkn4wOiDJJ1aUsr070vCVFl4O31tleZSJT67T/SBpdp\np7fAjm5fCGKfZGSebjAr83rKn0kjm2h4h0yar0xALNsJwLt5ebHmAVeIYT0V/pkV\nrhIFQpsGQPghxA/cN+knJDsUbgpCyMHmPg5Z8OnMITncYpAkjXW+Zq/ZGsULBp3c\nXWCWquVuWBbGkFR8eekRbqlkGOZ5wlsisyi/iQlKiu5TY1NLBga44Os099WA8xHW\n1THF5mJfuAnUhbPXIZOsad2aAEg5focwIi0Q+IUykyn85nD7mrMEZhxgu5+fk3MV\naKTRcaZtVb67hHGuITCBoTUoBYc0USgD4kRnlrfYU5LdTO2GSJaWOauH0VwjGOy1\nFcSRtAmoc1Wq4QC6chaLkZfXJ1FWMvScTOu3ulQL81bRabK8MzIswJGoYEJzVqer\nQqZvlBDSlmCH32RFrAbE2K8K91dvYB/teq5PH3JhmOAdQtwubnwYwxd31hUVsQzB\nDF+xC52u4ts+IzsyRBy0b+2dg4KW5IdXJlJeVKbNODS9zvKHrqKO6VpznMfIdMOY\nhrzJq5R5yy9AyYIMSQ3i0f1FF/+x6eZnXAi3siGVAbscsmTuyyZgVH3EUzckOGSp\nFTCFEZ3wfcigj9yhzFVFieECAwEAAQ==\n-----END RSA PUBLIC KEY-----\n"}}

Step 4: Generate Entity Secret Ciphertext

With the public key and entity secret in hand, we are now ready to encrypt the latter using RSA encryption and converting it into base64 format.

The easiest way to do this is via node and npm. Be sure you have installed the latest versions of each. Next, create a node project and install the node-forge package using the following terminal commands:


$ mkdir dev-wallet && cd dev-wallet
$ npm init -y
$ npm install node-forge

In the project, create a new file called encrypt.js and add the following code:


const forge = require('node-forge')

const entitySecret = forge.util.hexToBytes('YOUR_ENTITY_SECRET')
const publicKey = forge.pki.publicKeyFromPem('YOUR_PUBLIC_KEY')
const encryptedData = publicKey.encrypt(entitySecret, 'RSA-OAEP', {
  md: forge.md.sha256.create(),
  mgf1: {
    md: forge.md.sha256.create(),
  },
})

console.log(forge.util.encode64(encryptedData))

You should get output that looks something like this:


hjG9/qJZ+dDCsvJLKqDE1aBryaMTMQWKK/K5jzxJ1tTbivGIzR3anIxYjSDpyVMCNPyxwGr35HmVlAuLBYtNqFcX0HtzxAo3xngmaXNX5lmAg9M69h+lkN0VZ0xzKz0F4HFwhyGSujMfJ+QjID1iFWAUZXtLcH0oqmsnlsMv3xpcj8fgl8QlmBoIpgTElm7o0EycsOAAUVrpMjvIHvtU7udJywFzqcNrXJQtiDLUNICEXlY49NeHQMEbxQv8svRonXnNBIjWF3vOWZlqZwWtle/ww42R+TRPpH/bIAvv26yalt8K/EqgXPDBuYyHJhNWmBnOtv31O8TrVaHmXydKHK6BEgmGYAUHC2XKZYohLhfrfeDRhQAL0Mu8w3lIrEFeyQSanDJNHhcA1XRe9BcZ0aw+ylp1xUUr5bNCpYl6lB7Qgm6rBuPhNxPrFDQafC8pc0MtNBL6XHMvyrj56L8wc8bVUgOOzlcvnQQ52nMBHOyf9Gx9+qd3wcgDwrPgIyEE8QNj8uCfRWp8tJ5dxV0Xm25ui+j7WI293Os2gV7NGajl9jI2JL5Y1KMSGBzlfWXd/88A7k7Va+Hegk1KhtwxpXPs+LjOF44Kxbbl5Tqu6wZwZY7u+ihs7AT3AFxbsuQkG3BMxR1p1BY18oFIRHEW4+DbNfYHFryb5/IMOcG2eXk=

This is a base64 encrypted ciphertext that is exactly 684 characters long. We’re all set to register.

Step 5: Register with the Configurator

Let’s return to the Web3 Services console and from the left menu, choose the Configurator under dev-controlled wallets.

Here, we have the option to register our entity ciphertext. This ensures that our critical API requests, such as creating wallets and conducting transactions, are processed using the ciphertext as a validator.

image6-2

Enter the ciphertext created in the previous step and click on Register.

Doing so will prompt Circle to download a recovery file on your behalf. This file is useful if the original entity secret is lost and you don’t want to lose control of all generated wallets.

Step 6: Create a Wallet Set

A wallet set is a set of wallets generated using the same cryptographic key.

Using our ciphertext, let’s proceed to create a wallet set using the following API call.


curl --request POST \
     --url 'https://api.circle.com/v1/w3s/developer/walletSets' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: Bearer ' \
     --data '
{
  "idempotencyKey": "8f459a01-fa23-479d-8647-6fe05526c0df",
  "name": "Entity WalletSet A",
  "entitySecretCiphertext": ""
}

This will give you output that looks something like this:


{"data":{"walletSet":{"id":"018b62c4-a4b4-7bbb-babf-0303e1727fa4","custodyType":"DEVELOPER","name":"Entity WalletSet A","updateDate":"2023-10-24T17:38:56Z","createDate":"2023-10-24T17:38:56Z"}}

Note that the entity secret ciphertext must be different every run. You can regenerate a new key everytime by simply running:


$ node encrypt.js

Step 7: Create Wallets

The final step is to create dev-controlled wallets using our wallet set and a regenerated entity ciphertext.


curl --request POST \
     --url 'https://api.circle.com/v1/w3s/developer/wallets' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: Bearer ' \
     --data '
{
  "idempotencyKey": "0189bc61-7fe4-70f3-8a1b-0d14426397cb",
  "blockchains": [
    "MATIC-MUMBAI"
  ],
  "count": 2,
  "entitySecretCiphertext": "",
  "walletSetId": "018b62c4-a4b4-7bbb-babf-0303e1727fa4"
}

You should get wallets that look something like this:


{"data":{"wallets":[{"id":"448a8315-53b8-439a-bc9e-cb48df99aa14","state":"LIVE","walletSetId":"018b62c4-a4b4-7bbb-babf-0303e1727fa4","custodyType":"DEVELOPER","address":"0xcc2a067362bdc467bfba48d76d4efee8ad462e57","blockchain":"MATIC-MUMBAI","accountType":"EOA","updateDate":"2023-10-24T17:49:18Z","createDate":"2023-10-24T17:49:18Z"},{"id":"9e389fdb-1774-4367-b4db-70fa98db6d75","state":"LIVE","walletSetId":"018b62c4-a4b4-7bbb-babf-0303e1727fa4","custodyType":"DEVELOPER","address":"0xae973df055b1af29c5bcbd263e4cd363db5c446a","blockchain":"MATIC-MUMBAI","accountType":"EOA","updateDate":"2023-10-24T17:49:18Z","createDate":"2023-10-24T17:49:18Z"}]}}

Congratulations! You just created dev-controlled wallets.

Using these wallets and Circle API enables you to conduct transactions for your users such as minting NFTs, transferring tokens, creating digital signatures, and more.

Setting Up a User-Controlled Wallet

Setting up a user-controlled wallet is also straightforward and involves setting the user’s PIN code and security questions. You can follow a detailed tutorial for user-controlled wallets here.

Circle Web3 Services

With Circle’s Web3 Services, you can monitor all your wallets—dev-controlled or user-controlled—and their associated transactions.

You can also take a look at the wallets created by you in the Wallets section.

image4-2

Conclusion

Wallets play a critical role across Web3 apps. Simplifying their UX is the first step towards mass adoption of Web3.

With Programmable Wallets, Web3 user experiences are nearly indistinguishable from Web2—and makes creating these experiences on a variety of blockchains a breeze for developers.

To get started with Programmable Wallets, check out the documentation available here.

Sign up for an account to get started.

New call-to-action

*Programmable Wallets application programming interface (“API”) is offered by Circle Technology Services, LLC (“CTS”). CTS is not a regulated financial services company and the API does not include financial, investment, tax, legal, regulatory, accounting, business, or other advice. For additional details, please click here to see the Circle Developer terms of service.

Back to top