Build on Flow | Learn FCL - 15. How to Add and Revoke Public Keys
Tags: javascript, onflow, fcl, buildonflow
Published: 2022-08-22 18:40:00

## Preface

One of the problems you might encounter, when you need to sign with a lot of transactions is inability to sign more than single transaction by account in single block. This happens because `Proposer` role is used to provide a `nounce`, which will be updated on account key only after transaction is sealed.

The solution - we need to add more keys 🔑✨!

## Overview

After you go through the code in this article you will know:

- how to discover public keys on account using Flow View Source
- how to add new `PublicKey` with set weight

### Wallet Limitations

While `Blocto` or `Lilico` will not allow you to use key with different index - other than 0 - in some cases it’s still valuable to add public key you can use programmatically to automate some tasks. The key with full weight will give you access to the account storage and ability to manipulate it.

### Investigation

Before we continue, let’s check our current account on Flow View Source - [0x5593df7d286bcdb8](https://flow-view-source.com/testnet/account/0x5593df7d286bcdb8/keys) 

> 😅 Considering how many times Codesandbox has been run, you probably will see multiple keys here, when you read it.
> 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnqql61mgfotjh4nwlsd.png)
 

You should see at least a single key with `weight` equal to 1000 (full weight).

### Step 1 - Installation

> 💡You can go and fork your work from previous article as it will be mostly the same :)
> 

Add `"@onflow/fcl"`, `elliptic` and `sha3` packages as your dependencies.

### Step 2 - Create a signer

You can copy/paste the content of `signer.js` file from previous article or follow the [instructions](https://www.notion.so/Build-on-Flow-Learn-FCL-14-How-to-Mutate-Chain-State-by-Signing-Transactions-with-a-Private-Key-d3129deb4f924007bf6411de0011424b) and make a new one.

### Step 3 - Configure FCL

We are not gonna use wallets in this example - consider this as homework assignment 😉 - so our config only needs access node url:

```jsx
config({ "accessNode.api": "https://rest-testnet.onflow.org" });
```

### Step 4 - Implement `addPublicKey`

Let’s make a new function called `addPublicKey`, which will:

- accept `PublicKey` as a string,
- prepare transaction to pass public key and `weight` as arguments
- sign and send aforementioned transaction to network

The process is similar to how we were cooking transactions in previous article:

```jsx
const addPublicKey = async (publicKey) => {
  const cadence = `
  transaction(publicKey: String, weight: UFix64) {
    prepare(signer: AuthAccount) {
      let bytes = publicKey.decodeHex()

      let key = PublicKey(
        publicKey: bytes,
        signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
      )

      var clampledWeight = weight
      // weight should be in range 0 to 1000
      if(clampledWeight > 1000.0){
        clampledWeight = 1000.0
      }
  
      signer.keys.add(
        publicKey: key,
        hashAlgorithm: HashAlgorithm.SHA3_256,
        weight: clampledWeight
      )
    }
  }
  `;

  // List of arguments
	const weight = (0).toFixed(1) // zero weight keys are perfectly fine for Proposer role
  const args = (arg, t) => [
    arg(publicKey, t.String),
    arg(weight, t.UFix64)
  ];

  // Roles
  const proposer = signer;
  const payer = signer;
  const authorizations = [signer];

	// Execution limit
	const limit = 1000

  // "mutate" method will return us transaction id
  const txId = await mutate({
    proposer, payer, authorizations,
    cadence, args, limit
  });

	// Then we subscribe to status updates and return, when it's sealed
  return tx(txId).onceSealed();
};
```

### Step 5 - Implement `revokePublicKey`

Another function we would like to prepare is `revokePublicKey`. It will prepare and submit transaction, which will revoke the key on account:

```jsx
const revokePublicKey = async (keyIndex) => {
  const cadence = `
    transaction(keyIndex: Int){
      prepare(signer: AuthAccount){
        signer.keys.revoke(keyIndex:keyIndex)
      }
    }
  `;
  const args = (arg, t) => [arg(keyIndex.toString(), t.Int)];

  const proposer = signer;
  const payer = signer;
  const authorizations = [signer];

	const limit = 1000;

  // "mutate" method will return us transaction id
  const txId = await mutate({
    cadence, args, limit,
    proposer, payer, authorizations
  });

	// Then we subscribe to status updates and return, when it's sealed
  return tx(txId).onceSealed();
};
```

### Finally -

Let's add an IIFE at the end of the file and populate it with methods we have just defined:

```jsx
(async () => {
  console.clear();

  // PublicKey doesn't need to be unique, so we are gonna use exactly the same one
  // that already exist on account. This way we can control it with the same private key.
  const key =
    "790a6849decbc179e9904f7f601fbd629f1687f371484998ceb8c587303e05ae4f859c7aa91f8493642de1039039d2da9650b4b7d9d44d2486e7a2adabf602bc";

  // Uncomment this block to add public key
  /*
  const txDetails = await addPublicKey(key);
  console.log({ txDetails });
  */

  // Uncomment this block to revoke key
  /*
  const txDetails = await revokePublicKey(2);
  console.log({ txDetails });
  */
})();
```

When the dust settles, your console should have the output, showcasing that transaction succesfully updated your account:

```jsx
txDetails: {
	blockId: "b9ddfac94c968864ca369ec890e8025c0144375f334bd0e2ddea1965b175fc82",
	status: 4,
	statusString: "SEALED",
	statusCode: 0,
	errorMessage: "",
	events: Array(4),
	0: Object {
		type: "flow.AccountKeyAdded"
		transactionId: "fa2640f428a3317b656196ef7f069a744b2455569e492f8112d37abca31e273d"
		transactionIndex: 0
		eventIndex: 0
		data: Object
	},
	1: Object,
	2: Object,
	3: Object,
}
```

Checking Flow View Source will show there are now multiple keys that can be used:

If you uncomment the `revokePublicKey` usage block and wait for execution, you will be able to see that key is marked as revoked.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xb5ymv5k80l5a1q6l1z.jpg) 

> 💡 Please note, that keys are not `removed`, but `revoked` - you won’t be able to use this key index on this account anymore 🤷‍♂️
> 

Hope you’ve found this article useful. And if you have gone through it with us - you’ve grown stronger! 💪

![https://c.tenor.com/TgDOSZ0PpNsAAAAd/zoolander-boss.gif](https://c.tenor.com/TgDOSZ0PpNsAAAAd/zoolander-boss.gif)

Until next time 👋

## Resources

- **Full Source Code -** [https://codesandbox.io/s/dev-to-15-add-public-key-cvfho2](https://codesandbox.io/s/dev-to-15-add-public-key-cvfho2?file=/src/index.js)
- **Cadence Docs - Add Key -** [https://docs.onflow.org/cadence/language/accounts/#add-account-keys](https://docs.onflow.org/cadence/language/accounts/#add-account-keys)
- **Cadence Docs - Revoke Key -** [https://docs.onflow.org/cadence/language/accounts/#revoke-account-keys](https://docs.onflow.org/cadence/language/accounts/#revoke-account-keys)

Other resources you might find useful:

- **Flow Docs Site** - [https://docs.onflow.org/](https://docs.onflow.org/) - More detailed information about Flow blockchain and how to interact with it
- **Flow Portal** - [https://flow.com/](https://flow.com/) - your entry point to Flow
- **FCL JS** - [https://github.com/onflow/fcl-js](https://github.com/onflow/fcl-js) - Source code and ability to contribute to the FCL JS library
- **Cadence** - [https://docs.onflow.org/cadence/](https://docs.onflow.org/cadence/) - Introduction to Cadence
- **Codesandbox** - [https://codesandbox.io](https://codesandbox.io/) - An amazing in-browser IDE enabling quick prototyping