How to send a signature from a React App to a Node JS Server with ethereum-cryptography?

125 views Asked by At

I'm doing an exercise from Alchemy where I need to sign a transaction before sending it to the server. And then validate the transaction on the server side. I'm using a script to which I input a private key and message to generate the signature use here:

Note I need to convert the signMessage to String, otherwise I get a TypeError: Do not know how to serialize a BigInt:


  async function transfer(evt) {
    evt.preventDefault();
    const signMessage = {
      r: 36691152806955910003274360488470766136656266395316605280087404244279825225745n,
      s: 25775843654993118241418850103739194190473898130155752009759534141754021856163n,
      recovery: 0,
    };

    try {
      const {
        data: { balance },
      } = await server.post(`send`, {
        signature: signMessage.toString(),
      });
    } catch (ex) {
      console.log(ex);
      alert(ex.response.data.message);
    }
  }

Then I'm using this code on the server side, but it doesn't work. I cannot convert the String back to BigInt due to err SyntaxError: Cannot convert [object Object] to a BigIn:

app.post("/send", (req, res) => {
  // TODO: get a signature from the client-side app
  // recover the public address from the signature

  const { signature } = req.body;

  // Convert the strings back to BigInt and Buffer
  const signatureBigInt = BigInt(signature);
  console.log({ signatureBigInt });

  res.send("testing");
  
});

I've tried different things and convertion types but I think I'm missing something or I'm fundamentally wrong about what I'm doing.

2

There are 2 answers

0
Yilmaz On BEST ANSWER

From mdn doc:

When using the BigInt() function to convert a value to a BigInt, the value would first be converted to a primitive. Then, if it's not one of BigInt, string, number, and boolean, the error is thrown.

Looks like only BigInt, string, number, and boolean types can be converted.

Instead of stringifying the complete object, you should be stringifying the value of object key that you want to pass

0
lcnicolau On

Use this code in the frontend, which is the MDN recommendation for serialising BigInt:

BigInt.prototype.toJSON = function() { return this.toString() }

And then in the backend, use this code to deserialise and create a Signature instance:

const { transaction, signature } = req.body;
const { sender, recipient, amount } = transaction;
const { r, s, recovery } = signature;

const sig = new secp256k1.Signature(BigInt(r), BigInt(s), recovery);

From the Upgrading section of , note that:

Upgrading from 1.0 to 2.0:

  1. secp256k1 module was changed massively: before, it was using noble-secp256k1 1.7; now it uses safer noble-curves. Please refer to upgrading section from curves README. Main changes to keep in mind: a) sign now returns Signature instance b) recoverPublicKey got moved onto a Signature instance.