#How can I send transaction using soroban-client when I sign it with freighter wallet?

1 messages · Page 1 of 1 (latest)

acoustic bone
#

I'm using an example provided by soroban-client library
https://github.com/stellar/js-soroban-client/blob/main/docs/reference/examples.md

but instead of using sign method I return transaction.toEnvelope().toXDR('base64') and then sign that with my freighter wallet:

const signedTx = await signTransaction(txXDR, { network: 'FUTURENET', networkPassphrase: 'Test SDF Future Network ; October 2022', accountToSign: pubKey, });

SignedTx is transaction envelope xdr. Then I am able to get the transaction envelope object with:
const txEnvelope = SorobanClient.xdr.TransactionEnvelope.fromXDR( inputs.tx, 'base64' );

And Transaction object with:
const tx = txEnvelope.v1().tx();

But SorobanClient sendTransaction() method expects type Transaction<Memo<MemoType>, Operation[]> | FeeBumpTransaction

Has anyone figured how to sendTransaction when it's signed with freighter wallet?

GitHub

Main Soroban client library for the Javascript language - stellar/js-soroban-client

acoustic bone
#

My collegue figured it out.
We just build a SorobanClient.Transaction<SorobanClient.Memo<SorobanClient.MemoType>, SorobanClient.Operation[]> object with:

new SorobanClient.Transaction( txEnvelope, process.env.SOROBAN_NETWORK_PASSPHRASE );

cunning roost
#

Hi juico!
I've also faced the same problem but I wasn't sure how to do it.
So have u really signed transaction using Freighter api with that method?
And what does 'inputs.tx' mean in your code?

cunning roost
#

I've failed in signTransaction function with your method. Could u tell me the reason?

acoustic bone
#

@cunning roost The way I do it use a template from SorobanClient repo to create a transaction:

const account = await soroban_server.getAccount(
        inputs.publicKey
      );

      const keyPair = SorobanClient.Keypair.fromPublicKey(inputs.publicKey);
      const fee = '100';
      const contract = new SorobanClient.Contract(
        process.env.FUTURNET_PETAL_CONTRACT
      );

      const transaction_object = new SorobanClient.TransactionBuilder(account, {
        fee,
        networkPassphrase: SorobanClient.Networks.FUTURENET,
      })
        .addOperation(
          // An operation to call increment on the contract
          contract.call('set_test_int', {})
        )
        .setTimeout(30)
        .build();

      const transaction_ready = await soroban_server.prepareTransaction(
        transaction_object
      );

      return transaction_ready.toXDR();

Instead of signing it with the inbuilt SorobanClient method sigh I just return the transactionXDR

Then I sign the transactionXDR with freighter wallet:

      const signedTx = await signTransaction(txXDR, {
        network: 'FUTURENET',
        networkPassphrase: 'Test SDF Future Network ; October 2022',
        accountToSign: pubKey,
      });

I send the signedTx which is XDR for sending the transaction. First I get the TransactionEnvelope (the inputs.tx is signedTx):

    const txEnvelope = SorobanClient.xdr.TransactionEnvelope.fromXDR(
        inputs.tx,
        'base64'
      );

And I build the Transaction object that SorobanClient sendTransaction accepts:

      const tx = new SorobanClient.Transaction(
        txEnvelope,
        process.env.SOROBAN_NETWORK_PASSPHRASE
      );

And then send it:

let sendResponse: any = await soroban_server.sendTransaction(tx);

Mind you that SUCCESS response won't come right away. Will take couple of seconds. Hope this helps 🙂

cunning roost
#

I've coded as u wrote but signTransaction failed. Could u guess the reason?

cunning roost
#

I've got the following error:
Unable to send message to extension

acoustic bone
#

Where is your contract deployed? Futurenet?

cunning roost
#

Yeah. Deployed to FutureNet

acoustic bone
#

And your freighter is connected to futurenet?

#

Also your soroban server. How does the object look like?
I use this:

const soroban_server = new SorobanClient.Server(
'https://rpc-futurenet.stellar.org',
  { allowHttp: true }
);

And also make sure the wallet account you use for signing is in fact on futurenet

cunning roost
#

We're using the secure rpc url, then why do u specify { allowHttp: true }?

#

I removed it

acoustic bone
#

I don't remember where I saw it having a flag true, I left it there. Let me see what will happen when I set it on false

cunning roost
#

Plz

#

And txXDR = transaction.toEnvelope().toXDR() - Right?

#

I think the following code is right:
const txXDR = transaction.toEnvelope().toXDR('base64');

acoustic bone
#

Where do you use transaction.toEnvelope().toXDR?

cunning roost
#

Before calling signTransaction function

acoustic bone
#

Yeah it works without allowHttp for me.

cunning roost
#

I think so

acoustic bone
cunning roost
#

OK. Let me try again

acoustic bone
#

So basically:

const transaction_ready = await soroban_server.prepareTransaction(
        transaction_object
      );
transaction_ready.toXDR()

Then just use that for signTransaction

cunning roost
#

I see

#

I've got the same error

#

Unable to send message to extension

acoustic bone
#

Does it open frieghter for you to approve the transaction or just fails straight away?

cunning roost
#

Just occurs exception

#

Do u wanna read my full source code?

acoustic bone
#

How do you pass it to signTransaction?

#

I have it like this:

      const signedTxGetNonces = await signTransaction(txGetNoncesXDR, {
        network: 'FUTURENET',
        networkPassphrase: 'Test SDF Future Network ; October 2022',
        accountToSign: pubKey,
      });
cunning roost
#

What is txGetNoncesXDR?

#

Was it derived in the same way?

acoustic bone
#

Yeah that is just value I get from transaction_ready.toXDR()

cunning roost
#

I see but my code occurs exception

acoustic bone
#

Hmm, yeah you can show me the source code

cunning roost
#

Ok, I will

#

Here is the code:
const sourceAcc = await server.getAccount((await getUserInfo()).publicKey);
const defFee = '100';

const transaction0 = new SorobanClient.TransactionBuilder(sourceAcc, {
        fee: defFee, 
        networkPassphrase: SorobanClient.Networks.FUTURENET,
    }).addOperation(operation)
    .setTimeout(30)
    .build();

const transaction = await server.prepareTransaction(transaction0);
const txXDR = transaction.toXDR();
const signedTx = await signTransaction(txXDR, {
    network: 'FUTURENET',
    networkPassphrase: SorobanClient.Networks.FUTURENET,
    accountToSign: (await getUserInfo()).publicKey,
});
const txEnvelope = SorobanClient.xdr.TransactionEnvelope.fromXDR(signedTx, 'base64');
const tx = new SorobanClient.Transaction(txEnvelope, SorobanClient.Networks.FUTURENET);
#

This code is partial code of executeTransaction function and it takes operation as an input

acoustic bone
#

Try to use const account = await await server.loadAccount((await getUserInfo()).publicKey);

Instead of await server.getAccount((await getUserInfo()).publicKey);

Not sure the behaviour for this: accountToSign: (await getUserInfo()).publicKey,

Could you get the key before and then pass it in the accountToSign?

Also how does your operation looks like?

cunning roost
#

const res = await executeTransaction(/* adminKeypair, */
contract.call("set_fee",
SorobanClient.xdr.ScVal.scvU32(fee * 100), SorobanClient.xdr.ScVal.scvAddress(SorobanClient.xdr.ScAddress.scAddressTypeAccount(feeKeypair.xdrPublicKey())),
));

#

Then if your code, how is pubKey derived?

acoustic bone
#

I get it using getPublicKey method from @stellar/freighter-api

const pubKey = await getPublicKey();
acoustic bone
#

Oh yeah it is, I see it now

#

i build by operation like this:

      const contract = new SorobanClient.Contract(
        process.env.FUTURNET_PETAL_CONTRACT
      );

Where FUTURNET_PETAL_CONTRACT is contract address

Then in:
.addOperation( // An operation to call increment on the contract contract.call( 'safe_mint', SorobanClient.xdr.ScVal.scvAddress(to), SorobanClient.xdr.ScVal.scvU32(inputs.documentId), SorobanClient.xdr.ScVal.scvString(inputs.documentUri), SorobanClient.xdr.ScVal.scvVec(signers), SorobanClient.xdr.ScVal.scvString(inputs.documentHash), SorobanClient.xdr.ScVal.scvU64(deadline) ) )

cunning roost
#

I think they're same.
I've already sent transaction without signing in wallet api

acoustic bone
#

Ah ok

cunning roost
#

Still the same error, really stress

#

Then how did u get the variable 'to'?

#

In that url, I got the same error, too

acoustic bone
#

to is just a freighter public key

#

Yeah, signTransaction is exactly what I use

cunning roost
#

I think txXDR data is misconfigured

acoustic bone
#

I'm not sure, the error you're getting is not very specific which is a bummer :/

cunning roost
#

Plz help me once more.

cunning roost
acoustic bone
#

You can build with address class like this:
const to = new SorobanClient.Address(inputs.publicKey).toScAddress();

#

inputs.publicKey is just a stellar public key in a form of string

cunning roost
#

Thx. I'll try again

#

Same error

acoustic bone
# cunning roost Same error

I suggest to open a new thread specifically about this error, maybe others have the same issue and will know how to tackle it better