# Managed transaction (payer !== authorizations)

**URL:** <https://forum.flow.com/t/managed-transaction-payer-authorizations/1541>\
**Category:** Flow JavaScript SDK\
**Tags:** flow-sdk-js\
**Created:** [March 22, 2021, 3:00pm UTC](https://forum.flow.com/t/managed-transaction-payer-authorizations/1541 "2021-03-22T15:00:33Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![HMatthieu](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/hmatthieu/32/361_2.png) [@HMatthieu](https://forum.flow.com/u/HMatthieu)\
**Post date:** [March 22, 2021, 3:00pm UTC](https://forum.flow.com/t/managed-transaction-payer-authorizations/1541/1 "2021-03-22T15:00:33Z")

</div>

Hello folks,

I’m playing around with onflow/fcl but I’m stuck on something that I don’t understand. Looking for some explanation about signin transaction without using any wallet provider.

I wasn’t able to find anything on discord nor the forum, but please feel free to copy paste some doc or URL, I’ll be glad to read 🤓

Soo, here is my headache :  
From [this minimal reproducible example](https://github.com/hmatthieu/flow-transaction-sign/), you can directly jump on [the main](https://github.com/hmatthieu/flow-transaction-sign/blob/master/src/index.ts) or read the copy/paste here :

> **index.ts**
>
> ```auto
> import { SHA3 } from 'sha3';
> import * as Elliptic from 'elliptic';
> import * as fcl from '@onflow/fcl';
> 
> fcl.config().put('accessNode.api', 'https://access-testnet.onflow.org');
> 
> // eslint-disable-next-line new-cap
> const ec = new Elliptic.ec('p256');
> 
> // COPY PASTE FROM @qvvg : http://forum.flow.com/t/request-for-best-practices-re-wallet-account-creation-server-side/446/3#post_4
> 
> function hashMsgHex(msgHex: string) {
> const sha = new SHA3(256);
> sha.update(Buffer.from(msgHex, 'hex'));
> return sha.digest();
> }
> 
> function signWithKey(privateKey: string, data: string) {
> const key = ec.keyFromPrivate(Buffer.from(privateKey, 'hex'));
> const sig = key.sign(hashMsgHex(data));
> const n = 32; // half of signature length?
> const r = sig.r.toArrayLike(Buffer, 'be', n);
> const s = sig.s.toArrayLike(Buffer, 'be', n);
> return Buffer.concat([r, s]).toString('hex');
> }
> 
> // END COPY/PASTE
> 
> interface Account {
> address: string;
> publicKey: string;
> privateKey: string;
> keyId: number;
> }
> 
> export const buildAuthorization = ({ address, keyId, privateKey }: Account) => (
> account: any
> ) => ({
> ...account,
> tempId: address,
> addr: address,
> keyId: keyId,
> resolve: null,
> signingFunction: (data: any) => {
> return {
> addr: address,
> keyId: keyId,
> signature: signWithKey(privateKey, data.message),
> };
> },
> });
> 
> const admin: Account = {
> address: '0x3b814323826c6a63',
> publicKey:
> '2db41d2982317754f477dfab19aecc9d1fcdef382fd35444b35afbd3645e49f3e55a53dcb293fe54e2741a5b12159c76b29bd2b80f4fd7ea9c47c637a033a03d',
> privateKey:
> 'e83db5cd93ecd4ec28cdaf425de0c60acc4cdb9a00950312b6b6b5d0722dd703',
> keyId: 0,
> };
> 
> const user: Account = {
> address: '0xdfe6fafe93966abc',
> publicKey:
> '151518e2e990e714ca32025c03936cd2104890a8d64f651a619a80ef1b28fdbcef5613d2a92c80df3d13f4e166dffcd36d459c655ca631bfb196a8ac19908e1f',
> privateKey:
> '5bc078d3a1f8a439230268c71063ca066922c97ab5aa09f2da9162a50abe84a9',
> keyId: 0,
> };
> 
> async function handleTransaction(description: string, args: any) {
> try {
> console.log(description);
> const transaction = await fcl.send(args);
> console.log('-->', transaction.transactionId);
> await fcl.tx(transaction).onceSealed();
> console.log('OK');
> } catch (e) {
> console.log('KO : ', e);
> }
> }
> 
> async function run() {
> console.log('Ping...');
> await fcl.send([fcl.ping()]);
> console.log('OK');
> 
> await handleTransaction('Simple transaction...', [
> fcl.transaction`
> transaction() {
> prepare(account: AuthAccount) {
> log("Hello World");
> }
> }
> `,
> fcl.payer(buildAuthorization(admin)),
> fcl.proposer(buildAuthorization(admin)),
> fcl.authorizations([buildAuthorization(admin)]),
> ]);
> 
> await handleTransaction('Simple managed transaction...', [
> fcl.transaction`
> transaction() {
> prepare(account: AuthAccount) {
> log("Hello World");
> }
> }
> `,
> fcl.payer(buildAuthorization(admin)),
> fcl.proposer(buildAuthorization(admin)),
> fcl.authorizations([buildAuthorization(user)]),
> ]);
> 
> await handleTransaction('Multi managed transaction payer === proposer...', [
> fcl.transaction`
> transaction() {
> prepare(accountA: AuthAccount, accountB: AuthAccount) {
> log("Hello World");
> }
> }
> `,
> fcl.payer(buildAuthorization(admin)),
> fcl.proposer(buildAuthorization(admin)),
> fcl.authorizations([buildAuthorization(user), buildAuthorization(admin)]),
> ]);
> 
> await handleTransaction('Multi managed transaction payer !== proposer...', [
> fcl.transaction`
> transaction() {
> prepare(accountA: AuthAccount, accountB: AuthAccount) {
> log("Hello World");
> }
> }
> `,
> fcl.payer(buildAuthorization(admin)),
> fcl.proposer(buildAuthorization(user)),
> fcl.authorizations([buildAuthorization(user), buildAuthorization(admin)]),
> ]);
> }
> 
> run().catch(console.error);
> 
> ```

_Note that all privates keys/address/config are real but I created them only for this example._

Executing this file will log :

```auto
Ping...
OK

Simple transaction...
--> 8f13a80e70366993cf41b2f344a10f1a5a3a1fd43dd24bfcea89f1dfc8b43c2b
OK

Simple managed transaction...
--> 43c3d97a355064cb633a9e5d3006b2e2a43499b26165306882396e13028b7fef
KO : invalid signature: signature could not be verified using public key with index 0 on account 3b814323826c6a63

Multi managed transaction payer === proposer...
--> 824fa5d43ae620f58d59bee101e6fe0afaa9f0232ec6cee074a2d24df47244e3
KO : invalid signature: signature could not be verified using public key with index 0 on account 3b814323826c6a63

Multi managed transaction payer !== proposer...
--> dcac475352a94925fb5ac9b7c5529374406dd283562eac7fdd0adddbbbabd5b5
OK

```

What I don’t understand is that multi-sign transaction using a payer different than the proposer is working but every other multi transaction is not… I also tryied to manage myself the sequenceNum but I had the same result.

@qvvg I’m pinging you since I already spoke with you (some time ago, Binou on discord), and I copy paste some of your code héhé 👼

I’m not really looking for some debugging here, I’m just trying to understand how to code the authorization/signing function to have it consistently work, either with a multi-sign or with an account that pay & propose the transaction for avoiding to my users to pay.

Thanks for your help, and if you have any question, I’m here or on discord (@Binou)

---

<div class="post-metadata">

**Author:** ![HMatthieu](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/hmatthieu/32/361_2.png) [@HMatthieu](https://forum.flow.com/u/HMatthieu)\
**Post date:** [March 22, 2021, 3:05pm UTC](https://forum.flow.com/t/managed-transaction-payer-authorizations/1541/2 "2021-03-22T15:05:36Z")

</div>

OK so just to summarize because the code could be a little bit hard to read :

> **Using a self signin mechanism**
>
> ```auto
> // eslint-disable-next-line new-cap
> const ec = new Elliptic.ec('p256');
> 
> // COPY PASTE FROM @qvvg : http://forum.flow.com/t/request-for-best-practices-re-wallet-account-creation-server-side/446/3#post_4
> 
> function hashMsgHex(msgHex: string) {
> const sha = new SHA3(256);
> sha.update(Buffer.from(msgHex, 'hex'));
> return sha.digest();
> }
> 
> function signWithKey(privateKey: string, data: string) {
> const key = ec.keyFromPrivate(Buffer.from(privateKey, 'hex'));
> const sig = key.sign(hashMsgHex(data));
> const n = 32; // half of signature length?
> const r = sig.r.toArrayLike(Buffer, 'be', n);
> const s = sig.s.toArrayLike(Buffer, 'be', n);
> return Buffer.concat([r, s]).toString('hex');
> }
> 
> // END COPY/PASTE
> 
> interface Account {
> address: string;
> publicKey: string;
> privateKey: string;
> keyId: number;
> }
> 
> export const buildAuthorization = ({ address, keyId, privateKey }: Account) => (
> account: any
> ) => ({
> ...account,
> tempId: address,
> addr: address,
> keyId: keyId,
> resolve: null,
> signingFunction: (data: any) => {
> return {
> addr: address,
> keyId: keyId,
> signature: signWithKey(privateKey, data.message),
> };
> },
> });
> 
> ```

A transaction like this is OK :

```auto
fcl.send([
    fcl.transaction`
      transaction() {
        prepare(accountA: AuthAccount, accountB: AuthAccount) {
          log("Hello World");
        }
      }
    `,
    fcl.payer(buildAuthorization(admin)),
    fcl.proposer(buildAuthorization(user)),
    fcl.authorizations([buildAuthorization(user), buildAuthorization(admin)]),
  ]);

```

But this one (only the proposer changed) is KO (due to invalid signature error) :

```auto
fcl.send([
    fcl.transaction`
      transaction() {
        prepare(accountA: AuthAccount, accountB: AuthAccount) {
          log("Hello World");
        }
      }
    `,
    fcl.payer(buildAuthorization(admin)),
    fcl.proposer(buildAuthorization(admin)),
    fcl.authorizations([buildAuthorization(user), buildAuthorization(admin)]),
  ]);

```

---

<div class="post-metadata">

**Author:** ![HMatthieu](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/hmatthieu/32/361_2.png) [@HMatthieu](https://forum.flow.com/u/HMatthieu)\
**Post date:** [March 31, 2021, 8:21am UTC](https://forum.flow.com/t/managed-transaction-payer-authorizations/1541/3 "2021-03-31T08:21:40Z")

</div>

Sooo, just to keep updated, I finally found a solution.

It seems that the proposer must be one of the signer, and I now use different key for payer/proposer if its the same account (key with weight 1000 for a payer, key with weight 1 for proposer).

Works as I intended like this
