Build on Flow | Learn FCL - 14. How to Mutate Chain State by Signing Transactions with a Private Key
Tags: javascript, tutorial, onflow, fcl
Published: 2022-08-01 13:21:35

## Preface

Last time we covered how you can sign transactions with Lilico and Blocto wallets from the comfort of your browser. But it’s quite common that you might need to do the same task on a backend (i.e. server-side), where the browser is not available.

Fear not, my friend as this is exactly what we will teach you. After working through materials of this article you will know how to:

- fill different roles for your transaction
- get a basic understanding of the `multisig` process
- sign a transaction with your private key

### Step 1 - Installation

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

### Step 2 - Create a Signer

Let’s create a new file and call it `signer.js`. The file can have any name, we are just picking something with a semantic meaning here. Our signer will need to have 3 functions.

- First one will be called `hashMessageHex`- it will be used to hash the transaction message using a [SHA3 algorithm](https://en.wikipedia.org/wiki/SHA-3). The reason we are using SHA3 is because we’ve picked it as the `Hash Algorithm` during account creation on the [Testnet Faucet](https://testnet-faucet.onflow.org/) outlined in one of the previous articles. 
The function itself is pretty straightforward. We will take the transaction message, specifically packed and represented as hex string and feed it into the `update` method exposed by `SHA3` , then return the result from the `digest` method:

```jsx
const hashMessageHex = (msgHex) => {
  const sha = new SHA3(256);
  sha.update(Buffer.from(msgHex, "hex"));
  return sha.digest();
};
```

- The next function will call `signWithKey` - we will use it to sign our hashed transaction message with a private key. Now this IS a really complicated topic and let’s say you will cut a lot of corners if you simply copy-paste this one and do your crypto research later, mkey? 😅
**tldr**: we will use a **[Elliptic Curve Digital Signature Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)** in order to produce our signature:

```jsx
const signWithKey = (privateKey, msgHex) => {
  const key = curve.keyFromPrivate(Buffer.from(privateKey, "hex"));
  const sig = key.sign(hashMessageHex(msgHex));

  const n = 32;
  const r = sig.r.toArrayLike(Buffer, "be", n);
  const s = sig.s.toArrayLike(Buffer, "be", n);
  
return Buffer.concat([r, s]).toString("hex");
};
```

- The last one will be a `signer` function, which will be used as **[Authorization Function](https://docs.onflow.org/fcl/reference/api/#authorization-function) -** function which produce the information of the user that is going to sign and a `signing function` to use the information to produce a signature.

```jsx
export const signer = async (account) => {
  // We are hard coding these values here, but you can pass those values from outside as well.
  // For example, you can create curried function: 
  // const signer = (keyId, accountAdddress, pkey) => (account) => {...}
  // and then create multiple signers for different key indices 

  const keyId = Number(0); // always ensure that your keyId is a number not a string
  const accountAddress = "0x5593df7d286bcdb8";
  const pkey =
    "248f1ea7b4a058c39dcc97d91e6a5d0aa7afbc931428561b6efbc7bd0f5e0875";

  // authorization function need to return an account
  return {
    ...account, // bunch of defaults in here, we want to overload some of them though
    tempId: `${accountAddress}-${keyId}`, // tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId
    addr: sansPrefix(accountAddress), // the address of the signatory, currently it needs to be without a prefix right now
    keyId // this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string

    // This is where magic happens! ✨
    signingFunction: async (signable) => {
      // Singing functions are passed a signable and need to return a composite signature
      // signable.message is a hex string of what needs to be signed.
      const signature = await signWithKey(pkey, signable.message);

      return {
        addr: withPrefix(accountAddress), // needs to be the same as the account.addr but this time with a prefix, eventually they will both be with a prefix
        keyId, // needs to be the same as account.keyId, once again make sure its a number and not a string
        signature // this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed
      };
    }
  };
};
```

> ✨Please, note, that `signingFunction` is asynchronous, meaning that it can use Promises inside of its body to get a signature out of extension or remote server. Which is super handy, when you want to handle gas fees for your users 😉
> 

### Step 3 - FCL Setup

```jsx
import { config, query, mutate, tx } from "@onflow/fcl";
import { signer } from "./signer"

// Contrary to our wallet signing example, we don't need most of it in our config now
// so we'll get back to simple version
config({
  "accessNode.api": "https://rest-testnet.onflow.org",
  "0xBasic": "0xafabe20e55e9ceb6"
});
```

### Step 4 - Implement `readCounter`

We will copy the same function from our previous article, because it will behave absolutely the same:

```jsx
const readCounter = async () => {
  const cadence = `
    import Basic from 0xBasic

    pub fun main():UInt{
      return Basic.counter
    }
  `;
  const counter = await query({ cadence });
  console.log({ counter });
};
```

### Step 5 - Implement `shiftCounter`

`shiftCounter` function will be almost identical as well. The only difference is that this time we will fill all the roles, using our `signer` function. On top of that we will log how much time it took to seal the transaction, using `console.time` and `console.timeEnd` methods:

```jsx
const shiftCounter = async (value) => {
  console.log("%cSigning Transaction", `color: teal`);

  // Our Cadence code. Notice the use of alias here
  const cadence = `
    import Basic from 0xBasic

    transaction(shift: UInt8){
      prepare(signer: AuthAccount){
        Basic.incrementCounterBy(shift)
      }
    }
  `;

  // List of arguments
  const args = (arg, t) => [arg(value.toString(), t.UInt8)];
  const proposer = signer;
  const payer = signer;
  const authorizations = [signer];

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

  console.log(`Submitted transaction ${txId} to the network`);
  console.log("%cWaiting for transaction to be sealed...", `color: teal`);

  const label = "Transaction Sealing Time";
  console.time(label);
  
	// We will use transaction id in order to "subscribe" to it's state change and get the details
  // of the transaction
  const txDetails = await tx(txId).onceSealed();
  
  console.timeEnd(label);
  return txDetails;
};
```

### 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();
  await readCounter();

  const txDetails = await shiftCounter(12);
  console.log({ txDetails });

  // we will call "readCounter" function second time to ensure 
  // that value of counter has changed
  await readCounter();
})();
```

After the dust settles your console should have similar output:

```jsx
{counter: "655"}
Signing Transaction
Submitted transaction d88e98687dd98f7597aca9afaf3daaba788f644f90003c9b144bfa13440fd9ab to the network 
Waiting for transaction to be sealed...
Transaction Sealing Time: 14749.60000000149ms 
{txDetails: Object}
{counter: "667"}
```

![https://c.tenor.com/eIV3XiQyw4AAAAAC/you-did-it-willy-wonka-and-the-chocolate-factory.gif](https://c.tenor.com/eIV3XiQyw4AAAAAC/you-did-it-willy-wonka-and-the-chocolate-factory.gif)

It wasn’t that hard in the end, right? 😉

Until next time! 👋 

## Resources

- **Full Source Code -** [https://codesandbox.io/s/dev-to-14-mutate-with-pkey-d0jsj0](https://codesandbox.io/s/dev-to-14-mutate-with-pkey-d0jsj0?file=/src/index.js)
- **Package - SHA3** - [https://www.npmjs.com/package/sha3](https://www.npmjs.com/package/sha3)
- **Package - elliptic** - [https://www.npmjs.com/package/elliptic](https://www.npmjs.com/package/elliptic)
- **FCL - Authorization Function** - [https://docs.onflow.org/fcl/reference/api/#authorization-function](https://docs.onflow.org/fcl/reference/api/#authorization-function)

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